本文介绍了为什么即使我不调用get()或join(),此CompletableFuture也能正常工作?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在学习 CompletableFuture 时遇到了一个问题. get()/ join()方法正在阻止调用.如果我都不给他们打电话怎么办?

I had a question while studying CompletableFuture. The get()/join() methods are blocking calls. What if I don't call either of them?

此代码调用 get():

// Case 1 - Use get()
CompletableFuture.runAsync(() -> {
    try {
        Thread.sleep(1_000L);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
    System.out.println("Hello");
}).get();
System.out.println("World!");

Thread.sleep(5_000L); // Don't finish the main thread

输出:

Hello
World!

此代码既不调用 get(),也不调用 join():

This code calls neither get() nor join():

// Case 2 - Don't use get()
CompletableFuture.runAsync(() -> {
    try {
        Thread.sleep(1_000L);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
    System.out.println("Hello");
});
System.out.println("World!");

Thread.sleep(5_000L); // For don't finish main thread

输出:

World!
Hello

我不知道情况2的可运行块为何起作用.

I don't know why the runnable block of case 2 is working.

推荐答案

CompletableFuture 的整个思想是立即安排它们启动(尽管您无法可靠地确定它们在哪个线程中)将执行),并且当您到达 get join 时,结果可能已经准备好,即: CompletableFuture 可能已经完成.在内部,一旦管道中的某个阶段准备就绪,该特定的 CompletableFuture 将被设置为完成.例如:

The entire idea of CompletableFuture is that they are immediately scheduled to be started (though you can't reliably tell in which thread they will execute), and by the time you reach get or join, the result might already be ready, i.e.: the CompletableFuture might already be completed. Internally, as soon as a certain stage in the pipeline is ready, that particular CompletableFuture will be set to completed. For example:

String result =
   CompletableFuture.supplyAsync(() -> "ab")
                    .thenApply(String::toUpperCase)
                    .thenApply(x -> x.substring(1))
                    .join();

与以下内容相同:

CompletableFuture<String> cf1 = CompletableFuture.supplyAsync(() -> "ab");
CompletableFuture<String> cf2 = cf1.thenApply(String::toUpperCase);
CompletableFuture<String> cf3 = cf2.thenApply(x -> x.substring(1));
String result = cf3.join();

到您实际调用 join 的时间时, cf3 可能已经完成. get join 只是 block ,直到完成所有阶段为止,它不会触发计算;计算将立即安排.

By the time you reach to actually invoke join, cf3 might already finish. get and join just block until all the stages are done, it does not trigger the computation; the computation is scheduled immediately.

一个小的补充是,您可以完成 CompletableFuture ,而无需等待管道执行完成:例如 complete completeExceptionally obtrudeValue (即使已完成,也可以设置此值), obtrudeException cancel .这是一个有趣的示例:

A minor addition is that you can complete a CompletableFuture without waiting for the execution of the pipelines to finish: like complete, completeExceptionally, obtrudeValue (this one sets it even if it was already completed), obtrudeException or cancel. Here is an interesting example:

 public static void main(String[] args) {
    CompletableFuture<String> cf = CompletableFuture.supplyAsync(() -> {
        System.out.println("started work");
        LockSupport.parkNanos(TimeUnit.SECONDS.toNanos(5));
        System.out.println("done work");
        return "a";
    });

    LockSupport.parkNanos(TimeUnit.SECONDS.toNanos(1));
    cf.complete("b");
    System.out.println(cf.join());
}

这将输出:

started work
b

因此,即使工作开始了,最终值还是 b ,而不是 a .

So even if the work started, the final value is b, not a.

这篇关于为什么即使我不调用get()或join(),此CompletableFuture也能正常工作?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

07-31 20:38