Java Запустить задачу параллельно основному потоку, не блокируя ее

Я пытаюсь использовать функции Java 8 CompletableFuture, в которых говорится, что это дает возможность работать асинхронно. Но для того, чтобы выполнить то, что в «будущем», необходимо вызвать метод future.get(). Это блокирует основной поток. поскольку он ждет 30 секунд сна перед выполнением строки после future.get()

Есть ли способ добиться этого? Выполните неблокирующий способ выполнения я пытаюсь распечатать

"I'll run in the main thread."

до

"I'll run in a separate thread than the main thread."

public static void main(String[] args) throws ExecutionException, InterruptedException {


    CompletableFuture<Void> future = CompletableFuture.runAsync(new Runnable() {
        @Override
        public void run() {
            // Simulate a long-running Job
            try {
                TimeUnit.SECONDS.sleep(30);
            } catch (InterruptedException e) {
                throw new IllegalStateException(e);
            }
            System.out.println("I'll run in a separate thread than the main thread.");
        }
    });
    future.get();
    System.out.println("I'll run in the main thread.");
}
future.get() блокирует основной поток, поэтому оператор печати потока всегда будет выполняться перед печатью основного потока.
Lino 01.03.2019 14:23

@Lino, так что есть альтернатива?

Shenali Silva 01.03.2019 14:28

Вы можете просто переместить основной оператор печати доfuture.get(), но это кажется упрощенным, поэтому я не совсем уверен, в чем ваша проблема -> почему вам нужно, чтобы основное действие предшествовало действию потока

Lino 01.03.2019 14:30

нет смысла перемещать утверждение. фактический сценарий заключается в выполнении таймера параллельно основному потоку. но метод должен продолжать выполняться без блокировки на будущее. фактический сценарий - это вызов Rest, который попадает в метод конечной точки. но параллельное выполнение не должно блокировать метод конечной точки, возвращающий ответ

Shenali Silva 01.03.2019 14:33
CompletableFuture.runAsync( уже запускает другой ваш поток. Вызов future.get() — это просто способ дождаться окончания выполнения этого потока и получить его результат, прежде чем вы продолжите выполнение вызова в потоке.
xtratic 01.03.2019 14:34

Спецификации говорят, что CompletableFuture предназначен для неблокирующего запуска задач. но мне было интересно, как мы это делаем.

Shenali Silva 01.03.2019 14:35

@xtratic, что такое я не хочу ждать, пока этот поток завершит работу. Я пробовал без future.get(). хотя тогда основной поток не был заблокирован, он все равно не печатал то, что находится в потоке.

Shenali Silva 01.03.2019 14:38

CompletableFutureявляется работает без блокировки

xtratic 01.03.2019 14:42

@ShenaliSilva, когда вы удаляете вызов get(), основной поток не блокируется, и, поскольку в вашем упрощенном примере больше ничего нет, он завершится. JVM завершит работу, когда останутся только потоки Daemon, поэтому вы можете увидеть или не увидеть сообщение печати, в зависимости от непредсказуемого времени. Это не проблема реальных приложений. Но когда вы в упрощенном примере должны распечатать сообщение в фоновом потоке, вы должны подождать, прежде чем завершить его.

Holger 01.03.2019 15:09
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
0
9
1 857
2

Ответы 2

CompletableFuture.runAsync(Runnable) уже запускает другой ваш поток. Вызов future.get() — это просто способ дождаться окончания выполнения этого потока и получить его результат, прежде чем вы продолжите выполнение вызова в потоке.

Когда вы запускаете поток и get сразу, ничего не делая между ними (как вы это делаете), тогда нет смысла запускать поток.

фактический сценарий заключается в выполнении таймера параллельно основному потоку. но метод должен продолжать выполняться без блокировки на будущее. фактический сценарий - это вызов Rest, который попадает в метод конечной точки. но параллельное выполнение не должно блокировать метод конечной точки, возвращающий ответ

Shenali Silva 01.03.2019 14:39

То, чего вы пытаетесь достичь, не будет таким тривиальным, если я правильно понял. У вас есть входящий вызов, и вы хотите обработать этот вызов без вмешательства, и наряду с этим потоком вы хотите запустить отдельный процесс, независимый от основного процесса. (Поправьте меня, если я неправильно понял)

Я бы решил это с помощью очереди. Вы основной поток отправляете что-то в очередь и выполняете то, что ему нужно для выполнения. Затем есть отдельные потребители, прослушивающие очередь, которые будут выполнять другой процесс, не влияя на основной поток.

Другие вопросы по теме