Выполнить асинхронные действия в последовательности - PullRequest
0 голосов
/ 21 сентября 2018

У меня есть последовательность операций ввода-вывода (БД, устройства ввода-вывода ...), которые необходимо выполнить последовательно.

@SafeVarargs
public final CompletableFuture<Boolean> execute(final Supplier<Boolean>... methods)
{
    CompletableFuture<Boolean> future = null;

    for (Supplier<Boolean> method : methods)
    {
        if (future == null)
        {
            future = CompletableFuture.supplyAsync(method, threadPool);
        }
        else
        {
            future.thenCombineAsync(CompletableFuture.supplyAsync(method, threadPool), (result, currentResult) -> result && currentResult,
                    threadPool);
        }
    }

    return future.exceptionally(this::onException);
}

Мой код выполняется случайным образом.

  1. Что я могу сделать, чтобы обеспечить заказ?
  2. Как я могу объединить результаты в конце?Если бы все было верно, например?
  3. Чтобы применить обратный вызов после того, как все выполнено, чтобы проверить результат?

1 Ответ

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

Ваше текущее решение вызывает supplyAsync() немедленно и позже пытается объединить результаты.

Если вы хотите гарантировать последовательное выполнение, вы должны использовать thenApply() или thenCompose() вместо thenCombine():

for (Supplier<Boolean> method : methods)
{
    if (future == null)
    {
        future = CompletableFuture.supplyAsync(method, threadPool);
    }
    else
    {
        future.thenApplyAsync(result -> result && method.get(), threadPool);
    }
}

Обратите внимание, что это не вызовет method.get() у следующих поставщиков, если любой из них вернет false, поскольку && имеет короткое замыкание.Вы можете в любом случае использовать один & для принудительного вызова или поменять местами параметры.

Это уже объединяет все логические результаты в конце.Вы можете добавить что-нибудь к результирующему future после цикла, например, дополнительные вызовы thenApply() или блокирующий вызов join() для получения Boolean.

Обратите внимание, что этот цикл также можно легко переписатьиспользуя потоки:

future = Arrays.stream(methods)
        .reduce(CompletableFuture.completedFuture(true),
                (f, method) -> f.thenApplyAsync(result -> result && method.get()),
                (f1, f2) -> f1.thenCombine(f2, (result1, result2) -> result1 && result2));
...