h.j*_*.k. 7 java completable-future
这是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);
}
Run Code Online (Sandbox Code Playgroud)
有点好奇,没有实际完成CompletableFuture从allOf(...),例如调用它join(),我得到以下输出:
I'm called.
java.util.concurrent.CompletableFuture@<...>[Not completed, 1 dependents]
java.util.concurrent.CompletableFuture@<...>[Completed normally]
java.util.concurrent.CompletableFuture@<...>[Completed normally]
Run Code Online (Sandbox Code Playgroud)
我可以知道是什么导致JVM处理/认为r1有1(估计数量)依赖CompletableFuture,而它决定直接完成r2和r3?我能看到的唯一区别就在于try-catch,答案就这么简单吗?
为了比较,我得到了预期的等待时间为5秒,并且当我实际上join()在最后进行时,我得到了以下输出.如果它有帮助,我在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);
Run Code Online (Sandbox Code Playgroud)
输出:
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]
Run Code Online (Sandbox Code Playgroud)
r1并且r2是CompletableFuture两个独立提交的异步任务.
我是否知道是什么导致JVM处理/认为r1具有1(估计数量)的依赖CompletableFuture,而它决定直接完成r2和r3
它没有.当你调用println这些实例时,r2并且r3已经正常完成(它们没有做太多).r1没有(完成它的线程很可能正在睡觉).
呼叫allOf没有阻止.它将返回CompletableFuture它自己的一个,当CompletableFuture你完成所有你完成时它将完成.您链中到另一个CompletableFuture与thenRun其中,因为r2和r3完成,只需要看r1,即.它完成时r1完成.
您选择放弃对此的引用,CompletableFuture但thenRun已安排提交的任务.如果你添加一个
Thread.sleep(6000);
Run Code Online (Sandbox Code Playgroud)
在原始程序结束时,您将看到完成End.时打印的日志r1,因此返回的日志thenRun.
请注意,除非另行指定,否则CompletableFuture(例如,通过提交supplyAsync)中的异步任务都在ForkJoinPool使用守护程序线程的默认值内运行.您的应用程序将在5s过去之前退出,除非您选择阻止某个地方并等待该时间过去.