CompletableFuture Supply Async иногда работает в основном потоке

Я экспериментировал с Java 8 CompletableFutures. Насколько я понимаю, вызов CompletableFuture.supplyAsync (поставщик поставщика, исполнитель-исполнитель) всегда будет запускать задание в потоке, предоставленном переданным в Executor, но я заметил, что он иногда запускается в основном потоке, когда поставщик, которому я передаю это довольно "просто". Мой тестовый код:

import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicInteger;

public class SyncTest {

    public static void main(String[] args) {
        ExecutorService pool = Executors.newFixedThreadPool(5);

        CompletableFuture<?>[] cfs = new CompletableFuture<?>[10];
        AtomicInteger mainCount = new AtomicInteger();
        for (int i = 0; i < cfs.length; i++) {
            int index = i;
            CompletableFuture<Integer> cf = 
CompletableFuture.supplyAsync(() -> {
                return index;
            }, pool).thenApply(j -> {
                if (Thread.currentThread().getName().equals("main")) {    
                    mainCount.incrementAndGet();
                }

                System.out.println(Thread.currentThread().getName() + ": " + index + ": doing a heavy computation");
                try {
                    Thread.sleep(10);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                return j;
            });
            cfs[i] = cf;
        }

        System.out.println(Thread.currentThread().getName() + " doing other stuff");
        try {
            Thread.sleep(10);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        CompletableFuture.allOf(cfs).join();
        pool.shutdown();
        System.out.println("Jobs on main: " + mainCount.get());
    }
}

И результат, который я получаю, выглядит примерно так:

main: 0: doing a heavy computation
main: 1: doing a heavy computation
pool-1-thread-3: 2: doing a heavy computation
pool-1-thread-4: 3: doing a heavy computation
main: 4: doing a heavy computation
main doing other stuff
pool-1-thread-4: 9: doing a heavy computation
pool-1-thread-5: 8: doing a heavy computation
pool-1-thread-2: 7: doing a heavy computation
pool-1-thread-1: 6: doing a heavy computation
pool-1-thread-3: 5: doing a heavy computation
Jobs on main: 3

Я понимаю, что это довольно тривиальный пример, и что есть другие методы для CompletableFutures, такие как thenSupplyAsync и completedFuture, для работы с ними, мне более любопытно, как вообще возможно, что некоторые из этих задач выполняются в основном потоке.

Отметьте ответы на этот вопрос: stackoverflow.com/questions/27723546/…

Ivan 18.05.2018 22:45

Возможный дубликат CompletableFuture, supplyAsync () и thenApply ()

Didier L 19.05.2018 16:11
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
3
2
1 840
1

Ответы 1

задача, которая печатает «выполнение тяжелых вычислений», вызывается с помощью thenApply, что означает, что вы не указали исполнителя для запуска этой задачи, и система может использовать любого исполнителя, включая текущий поток.

Если вы хотите, чтобы это задание выполнялось на предопределенном исполнителе, используйте вместо него thenApplyAsync, со вторым параметром - исполнителем или без него.

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