[英]When is CompletableFuture actually completed?
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);
}
Somewhat curiously, without actually completing the CompletableFuture
from allOf(...)
, eg calling its join()
, I get the following output: 有点奇怪的是,如果没有从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]
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
? 我是否知道是什么导致JVM处理/认为r1
具有1(估计数量)依赖的CompletableFuture
,而它决定直接完成r2
和r3
? The only difference I can see is just the try-catch
, so is the answer as simple as that? 我能看到的唯一区别就是try-catch
,答案就这么简单吗?
For comparison, I get the expected waiting time of 5 seconds and the following output when I actually do a join()
at the end. 为了比较,当我实际上在最后执行join()
时,我获得了5秒的预期等待时间和以下输出。 If it helps, I'm encountering this on Java 8 Update 40 JVM. 如果它有帮助,我在Java 8 Update 40 JVM上遇到这个问题。
Modification: 修改:
// ...
CompletableFuture.allOf(r1, r2, r3).thenRun(() -> { System.out.println("End."); }).join();
Stream.of(r1, r2, r3).forEach(System.out::println);
Output: 输出:
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
and r2
are CompletableFuture
s for two independently submitted async tasks. r1
和r2
是两个独立提交的异步任务的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 我是否知道是什么导致JVM处理/认为r1具有1(估计数量)的依赖CompletableFuture,而它决定直接完成r2和r3
It doesn't. 它没有。 By the time you call the println
on these instances, r2
and r3
have completed normally (they don't do much). 当你在这些实例上调用println
时, r2
和r3
已正常完成(它们没有做太多)。 r1
hasn't (the thread that would have completed it is most likely sleeping). r1
没有(完成它的线程很可能正在睡觉)。
The call to allOf
is not blocking. 对allOf
的调用没有阻塞。 It will return a CompletableFuture
of its own that will be completed when all the CompletableFuture
you gave them are done. 它将返回自己的CompletableFuture
,当您完成所有CompletableFuture
时,它将完成。 You chain that into another CompletableFuture
with thenRun
which, since r2
and r3
are done, simply depends on r1
, ie. 你用thenRun
它链接到另一个CompletableFuture
,由于r2
和r3
完成, thenRun
依赖于r1
,即。 it is completed when r1
completes. 它在r1
完成时完成。
You choose to discard the reference to this CompletableFuture
but the task submitted to thenRun
is scheduled. 您选择放弃对此CompletableFuture
的引用,但是已安排提交给thenRun
的任务。 If you add a 如果你添加一个
Thread.sleep(6000);
at the end of your original program, you'll see your End.
在原始程序结束时,您将看到您的End.
log printed when r1
completes and, consequently, the one returned by thenRun
. r1
完成时打印日志,然后是thenRun
返回的thenRun
。
Note that, unless otherwise specified, your async tasks within the CompletableFuture
(eg. submitted through supplyAsync
) are all ran within the default ForkJoinPool
which uses daemon threads. 请注意,除非另有说明,否则CompletableFuture
异步任务(例如,通过supplyAsync
提交)都在使用守护程序线程的默认ForkJoinPool
运行。 Your application will exit before the the 5s has elapsed unless you choose to block somewhere and wait for that time to pass. 您的应用程序将在5s过去之前退出,除非您选择阻止某个地方并等待该时间过去。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.