问题描述
我在学习 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也能正常工作?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!