[英]Only execute CompletableFuture callback when status of result is completed
[英]When is CompletableFuture actually completed?
这是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处理/认为r1
具有1(估计数量)依赖的CompletableFuture
,而它决定直接完成r2
和r3
? 我能看到的唯一区别就是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]
r1
和r2
是两个独立提交的异步任务的CompletableFuture
。
我是否知道是什么导致JVM处理/认为r1具有1(估计数量)的依赖CompletableFuture,而它决定直接完成r2和r3
它没有。 当你在这些实例上调用println
时, r2
和r3
已正常完成(它们没有做太多)。 r1
没有(完成它的线程很可能正在睡觉)。
对allOf
的调用没有阻塞。 它将返回自己的CompletableFuture
,当您完成所有CompletableFuture
时,它将完成。 你用thenRun
它链接到另一个CompletableFuture
,由于r2
和r3
完成, thenRun
依赖于r1
,即。 它在r1
完成时完成。
您选择放弃对此CompletableFuture
的引用,但是已安排提交给thenRun
的任务。 如果你添加一个
Thread.sleep(6000);
在原始程序结束时,您将看到您的End.
r1
完成时打印日志,然后是thenRun
返回的thenRun
。
请注意,除非另有说明,否则CompletableFuture
异步任务(例如,通过supplyAsync
提交)都在使用守护程序线程的默认ForkJoinPool
运行。 您的应用程序将在5s过去之前退出,除非您选择阻止某个地方并等待该时间过去。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.