简体   繁体   English

CompletableFuture何时实际完成?

[英]When is CompletableFuture actually completed?

Here's the MCVE : 这是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);
}

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 ,而它决定直接完成r2r3 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. 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 我是否知道是什么导致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时, r2r3已正常完成(它们没有做太多)。 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 ,由于r2r3完成, 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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM