Java CompletableFutures : is it ever a acceptable to not join/get?

标签 java completable-future

不返回或加入 CompletableFuture 是否正确?

也就是说,这段代码是否正确?

void noJoin() {
   CompletableFuture<Void> cfa = CompletableFuture
                                   .supplyAsync(() -> "a")
                                   .thenAccept(this::someSideEffect);

   CompletableFuture<Void> cfb = CompletableFuture
                                   .supplyAsync(() -> "b")
                                   .thenAccept(this::someSideEffect);
}

在上面的代码中,我们永远不知道 Future 是否成功完成,或者根本不知道。 (我什至不知道在 noJoin 中创建的 Future 不符合垃圾回收条件;但大概 ForkJoinPool.commonPool() 保留了这些引用?)

无论如何,如果这些 Future 是否成功对我们的程序来说确实无关紧要,那么更好的 noJoin 实现只是一个空操作:

void noJoin() {}

如果另一方面,这确实很重要,我们需要通过组合它们(与 thenCompose 串行,或与 thenCombine 或 allOf 并行)来加入或返回两个 Future,然后加入组合的 Future 或将其返回给我们的调用者。

通过加入,如果 Future 异常,我们会阻塞并抛出异常;或者更好的是,通过返回 Future,我们保持异步,同时确保调用者获得包含任何异常结果的 Future:

Future<Void> returnBothAsync() {

       CompletableFuture<Void> cfa = CompletableFuture
                                       .supplyAsync(() -> "a")
                                       .thenAccept(this::someSideEffect);

       CompletableFuture<Void> cfb = CompletableFuture
                                       .supplyAsync(() -> "b")
                                       .thenAccept(this::someSideEffect);

       return CompletableFuture.allOf(cfa, cfb);
}

void joinBothBlocking() {

       CompletableFuture<Void> cfa = CompletableFuture
                                       .supplyAsync(() -> "a")
                                       .thenAccept(this::someSideEffect);

       CompletableFuture<Void> cfb = CompletableFuture
                                       .supplyAsync(() -> "b")
                                       .thenAccept(this::someSideEffect);

       CompletableFuture.allOf(cfa, cfb).get(50L, TimeUnit.MILLISECONDS);
}

即使我们安排处理所有异常,我认为也是如此:

void noJoin() {
   CompletableFuture<Void> cfa = CompletableFuture
                                   .supplyAsync(() -> "a")
                                   .thenAccept(this::someSideEffect)
                                   .exceptionally(e -> {
                                         Logger.log(e);
                                         return DEFAULT;
                                   });

   CompletableFuture<Void> cfb = CompletableFuture
                                   .supplyAsync(() -> "b")
                                   .thenAccept(this::someSideEffect);
}

因为即使异常被处理/“不可能发生”,我们仍然不知道 Future 是否已经完成。

或者我错了,在某些情况下,像 noJoin 中的代码是正确的?

最佳答案

这不是您问题的完整答案。这可能取决于确切的用例,以便能够判断如何处理 CompletableFuture 及其结果。

如果您选择不等待 CompletableFuture 的结果,您可能必须确保所使用的执行器完成所有任务。在您的情况下,使用的执行器是 ForkJoinPool.commonPool()其文档说:

[...] However this pool and any ongoing processing are automatically terminated upon program System.exit(int). Any program that relies on asynchronous task processing to complete before program termination should invoke commonPool().awaitQuiescence, before exit.

关于Java CompletableFutures : is it ever a acceptable to not join/get?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56914896/

相关文章:

java - CompletableFuture 已经完成但出现异常

multithreading - 在 supplyAsync 阻塞主线程后使用 thenAccept

java - Android 中的信标 - 教程中出现错误

java - JPA2 : deadlock using native query

java - 将指定对象从一个 ArrayList 复制到另一个

java - 当异步方法中某个线程发生异常时终止所有线程

Java 8 谓词

java - ArrayList.add() 无法正常工作

java-8 - Vertx 3 支持 CompletableFuture 吗?

java - 如何在可完成的 future 测试异常?