繁体   English   中英

CompletableFuture何时实际完成?

[英]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 ,而它决定直接完成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

我是否知道是什么导致JVM处理/认为r1具有1(估计数量)的依赖CompletableFuture,而它决定直接完成r2和r3

它没有。 当你在这些实例上调用println时, r2r3已正常完成(它们没有做太多)。 r1没有(完成它的线程很可能正在睡觉)。

allOf的调用没有阻塞。 它将返回自己的CompletableFuture ,当您完成所有CompletableFuture时,它将完成。 你用thenRun它链接到另一个CompletableFuture ,由于r2r3完成, thenRun依赖于r1 ,即。 它在r1完成时完成。

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

Thread.sleep(6000);

在原始程序结束时,您将看到您的End. r1完成时打印日志,然后是thenRun返回的thenRun


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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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