gpt4 book ai didi

java - CompletableFuture 什么时候真正完成?

转载 作者:塔克拉玛干 更新时间:2023-11-03 05:12:57 25 4
gpt4 key购买 nike

这是 MCVE :

public static void main(String[] args) {
CompletableFuture<String> r1 = CompletableFuture.supplyAsync(() -> {
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
return "41";
});
CompletableFuture<String> r2 = CompletableFuture.supplyAsync(() -> "42");
CompletableFuture<String> r3 = CompletableFuture.supplyAsync(() -> {
System.out.println("I'm called.");
return "43";
});
CompletableFuture.allOf(r1, r2, r3).thenRun(() -> { System.out.println("End."); });
Stream.of(r1, r2, r3).forEach(System.out::println);
}

有点奇怪,没有真正完成 allOf(...)CompletableFuture,例如调用它的 join(),我得到以下输出:

I'm called.
java.util.concurrent.CompletableFuture@<...>[Not completed, 1 dependents]
java.util.concurrent.CompletableFuture@<...>[Completed normally]
java.util.concurrent.CompletableFuture@<...>[Completed normally]

我可以知道是什么导致 JVM 处理/认为 r11 (estimated number of) dependent CompletableFuture , 而它决定直接完成 r2r3?我能看到的唯一区别就是 try-catch,那么答案就这么简单吗?

为了比较,当我最后执行 join() 时,我得到了 5 秒的预期等待时间和以下输出。如果有帮助,我会在 Java 8 Update 40 JVM 上遇到这个问题。

修改:

// ...
CompletableFuture.allOf(r1, r2, r3).thenRun(() -> { System.out.println("End."); }).join();
Stream.of(r1, r2, r3).forEach(System.out::println);

输出:

I'm called.
// <note: 5-second wait is here>
End.
java.util.concurrent.CompletableFuture@<...>[Completed normally]
java.util.concurrent.CompletableFuture@<...>[Completed normally]
java.util.concurrent.CompletableFuture@<...>[Completed normally]

最佳答案

r1r2 是两个独立提交的异步任务的 CompletableFuture

May I know what's causing the JVM to treat/think that r1 has 1 (estimated number of) dependent CompletableFuture, while it decides to straightforwardly complete r2 and r3

事实并非如此。当您在这些实例上调用 println 时,r2r3 已经正常完成(它们没有做太多事情)。 r1 还没有(完成它的线程很可能正在 hibernate )。

allOf 的调用没有阻塞。它会返回一个自己的 CompletableFuture,当你给它们的所有 CompletableFuture 都完成时,它就会完成。你用 thenRun 将它链接到另一个 CompletableFuture 中,因为 r2r3 已经完成,所以只依赖于 r1,即。它在 r1 完成时完成。

您选择放弃对该 CompletableFuture 的引用,但提交给 thenRun 的任务已安排。如果你添加一个

Thread.sleep(6000);

在原始程序的末尾,您会看到 End. 日志在 r1 完成时打印,因此 thenRun< 返回的日志.


请注意,除非另有说明,否则 CompletableFuture 中的异步任务(例如通过 supplyAsync 提交)都在默认的 ForkJoinPool 中运行> 使用守护线程。您的应用程序将在 5 秒过去之前退出,除非您选择阻塞某处并等待该时间过去。

关于java - CompletableFuture 什么时候真正完成?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30857778/

25 4 0