CompletableFuture allof (..). Join () против CompletableFuture.join () - PullRequest
0 голосов
/ 17 сентября 2018

В настоящее время я использую метод CompAstableFuture supplyAsync () для отправки некоторых задач в общий пул потоков. Вот как выглядит фрагмент кода:

final List<CompletableFuture<List<Test>>> completableFutures = resolvers.stream()
        .map(resolver -> supplyAsync(() -> task.doWork()))
        .collect(toList());

CompletableFuture.allOf(completableFutures.toArray(new CompletableFuture[completableFutures.size()])).join();

final List<Test> tests = new ArrayList<>();
completableFutures.stream()
        .map(completableFuture -> completableFuture.getNow())
        .forEach(tests::addAll);

Хотелось бы узнать, чем ниже код отличается от кода выше. Я удалил родительский completetableFuture из приведенного ниже кода и добавил join () для каждого из CompletetableFuture вместо getNow ():

final List<CompletableFuture<List<Test>>> completableFutures = resolvers.stream()
        .map(resolver -> supplyAsync(() -> task.doWork()))
        .collect(toList());

final List<Test> tests = new ArrayList<>();
completableFutures.stream()
        .map(completableFuture -> completableFuture.join())
        .forEach(tests::addAll);

Я использую это в сервисе Spring, и есть проблемы с исчерпанием пула потоков. Любые указатели высоко ценятся.

1 Ответ

0 голосов
/ 20 сентября 2018

Прежде всего, .getNow() не работает, так как этот метод требует запасного значения в качестве аргумента для случая, когда будущее еще не завершено.Поскольку вы предполагаете, что будущее здесь будет завершено, вы должны также использовать join().

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

Единственный способ избежать этого - это рефакторинг кода, чтобы не ожидать результата синхронно, а вместо этого запланировать последующее действие обработки, которое будет выполнено, когда все задания будут завершены.Затем использование allOf становится актуальным:

final List<CompletableFuture<List<Test>>> completableFutures = resolvers.stream()
    .map(resolver -> supplyAsync(() -> task.doWork()))
    .collect(toList());

CompletableFuture.allOf(completableFutures.toArray(new CompletableFuture<?>[0]))
    .thenAccept(justVoid -> {
        // here, all jobs have been completed
        final List<Test> tests = completableFutures.stream()
            .flatMap(completableFuture -> completableFuture.join().stream())
            .collect(toList());
        // process the result here
    });

Кстати, что касается метода toArray для коллекций, я рекомендовал прочитать Массивы мудрости Древних

...