CompletableFuture何时实际完成?

时间:2015-06-16 02:14:50

标签: 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);
}

有点奇怪,没有真正完成CompletableFuture的{​​{1}},例如调用它的allOf(...),我得到以下输出:

join()

我是否知道导致JVM处理/认为I'm called. java.util.concurrent.CompletableFuture@<...>[Not completed, 1 dependents] java.util.concurrent.CompletableFuture@<...>[Completed normally] java.util.concurrent.CompletableFuture@<...>[Completed normally] 1 (estimated number of) dependent CompletableFuture的原因,而它决定直接完成r1r2?我能看到的唯一区别就是r3,答案就这么简单了吗?

为了进行比较,我得到了预期的5秒等待时间以及当我在结尾处实际进行try-catch时的以下输出。如果有帮助,我会在Java 8 Update 40 JVM上遇到这种情况。

修饰:

join()

输出:

// ...
CompletableFuture.allOf(r1, r2, r3).thenRun(() -> { System.out.println("End."); }).join();
Stream.of(r1, r2, r3).forEach(System.out::println);

1 个答案:

答案 0 :(得分:6)

对于两个独立提交的异步任务,

r1r2CompletableFuture

  

我可以知道是什么导致JVM对待/认为r1有1   (估计数量)依赖CompletableFuture,而它决定   直截了当地完成r2和r3

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

allOf的调用没有阻止。它将返回自己的CompletableFuture,当您完成所有CompletableFuture时,它将完成。您将其链接到另一个CompletableFuture thenRun,其中r2r3完成后,只需依赖r1,即。它在r1完成时完成。

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

Thread.sleep(6000);

在原始程序结束时,您会在End.完成时看到您的r1日志,因此,thenRun返回的日志会打印出来。

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