CompletableFuture-汇总未来的快速失败

jwa*_*jwa 5 java java.util.concurrent completable-future

我一直在使用CompletableFuture.allOf(...)帮助程序来创建汇总期货,这些期货只有在其复合期货标记为已完成时才会变为“完成”,即:

CompletableFuture<?> future1 = new CompletableFuture<>();
CompletableFuture<?> future2 = new CompletableFuture<>();
CompletableFuture<?> future3 = new CompletableFuture<>();

CompletableFuture<?> future = CompletableFuture.allOf(future1, future2, future3);
Run Code Online (Sandbox Code Playgroud)

我希望对此功能稍作更改,在以下情况下,总的未来市场是完整的:

  • 所有期货均已成功完成
  • 任何一个未来都没有成功完成

在后一种情况下,合计期货应立即(例外)完成,而不必等待其他期货完成(即快速失败)

为了说明这一点,请CompletableFuture.allOf(...)考虑一下:

// First future completed, gotta wait for the rest of them...
future1.complete(null);
System.out.println("Future1 Complete, aggregate status: " + future.isDone());

// Second feature was erroneous! I'd like the aggregate to now be completed with failure
future2.completeExceptionally(new Exception());
System.out.println("Future2 Complete, aggregate status: " + future.isDone());

// Finally complete the third future, that will mark the aggregate as done
future3.complete(null);
System.out.println("Future3 Complete, aggregate status: " + future.isDone());
Run Code Online (Sandbox Code Playgroud)

使用allOf(...),此代码产生:

Future1 Complete, aggregate status: false
Future2 Complete, aggregate status: false
Future3 Complete, aggregate status: true
Run Code Online (Sandbox Code Playgroud)

鉴于这是个例外,我的替代聚合实现在Feature2完成后将返回“ true”。


我在Java标准库中找不到任何可以帮助我实现这一目的的工具,这感觉很奇怪……鉴于这是一个相对普通的用例。

从实现的角度CompletableFuture.allOf(...)来看,这些场景背后的逻辑非常复杂。我讨厌自己写这个,我想知道是否还有其他选择?

jwa*_*jwa 5

尽管在语法上不如该CompletableFuture.allOf(...)方法好,但似乎thenCompose(...)可以提供解决方案:

CompletableFuture<?> future = future1.thenCompose((f) -> future2).thenCompose((f) -> future3);
Run Code Online (Sandbox Code Playgroud)

这将产生所需的:

Future1 Complete, aggregate status: false
Future2 Complete, aggregate status: true
Future3 Complete, aggregate status: true
Run Code Online (Sandbox Code Playgroud)

这可以包含在一个辅助方法中,该方法将为调用者提供一些语法细节:

private static CompletableFuture<?> composed(CompletableFuture<?> ... futures) {

    // Complete when ALL the underlying futures are completed
    CompletableFuture<?> allComplete = CompletableFuture.allOf(futures);

    // Complete when ANY of the underlying futures are exceptional
    CompletableFuture<?> anyException = new CompletableFuture<>();
    for (CompletableFuture<?> completableFuture : futures) {
        completableFuture.exceptionally((t) -> {
            anyException.completeExceptionally(t);
            return null;
        });
    }

    // Complete when either of the above are satisfied
    return CompletableFuture.anyOf(allComplete, anyException);
}
Run Code Online (Sandbox Code Playgroud)

允许:

CompletableFuture<?> future = composed(future1, future2, future3);
Run Code Online (Sandbox Code Playgroud)