假设我有以下代码:
CompletableFuture<Integer> future
= CompletableFuture.supplyAsync( () -> 0);
thenApply
案例:
future.thenApply( x -> x + 1 )
.thenApply( x -> x + 1 )
.thenAccept( x -> System.out.println(x));
此处输出为2.现在为thenApplyAsync
:
future.thenApplyAsync( x -> x + 1 ) // first step
.thenApplyAsync( x -> x + 1 ) // second step
.thenAccept( x -> System.out.println(x)); // third step
我在此blog中读到,每个thenApplyAsync
都是在一个单独的帖子中执行的,同时&#39;(这意味着在thenApplyAsyncs
之前开始{之前} { {1}}完成),如果是这样,如果第一步没有完成,第二步的输入参数值是多少?
如果第二步不采取第一步的结果,将在何处进行? 第三步将采取哪一步结果?
如果第二步必须等待第一步的结果,那么thenApplyAsyncs
的重点是什么?
这里x - &gt; x + 1只是为了表明这一点,我想知道的是计算时间非常长。
答案 0 :(得分:19)
与负责运行代码的Executor
有所不同。 CompletableFuture
上的每个运营商通常有3个版本。
thenApply(fn)
- 在调用它的fn
定义的线程上运行CompleteableFuture
,因此您通常无法知道它将在何处执行。如果结果已经可用,它可能会立即执行。thenApplyAsync(fn)
- 在环境定义的执行程序上运行fn
,无论情况如何。对于CompletableFuture
,这通常为ForkJoinPool.commonPool()
。thenApplyAsync(fn,exec)
- 在fn
上运行exec
。最后结果是一样的,但调度行为取决于方法的选择。
答案 1 :(得分:1)
我必须指出,thenApply
和thenApplyAsync
这两个名字绝对是令人恐惧和困惑的。从这些方法的约定来看,thenApplyAsync
中没有什么比thenApply
更异步。
差异与在哪个线程上运行函数有关。提供给thenApply
may run on any of the threads的功能
complete
thenApply
thenApplyAsync
使用默认的Executor
(也称为线程池)或提供的Executor
。
这些函数的异步部分与以下事实有关:异步操作最终会调用complete
或completeExceptionally
。这个想法来自Javascript,与多线程无关。
答案 2 :(得分:0)
第二步(即计算)将始终在第一步之后执行。
如果第二步必须等待第一步的结果,那么异步的意义何在?
在这种情况下,异步意味着您可以保证该方法将快速返回并且计算将在另一个线程中执行。
在调用thenApply
时(没有异步),则没有这样的保证。在这种情况下,如果CompletableFuture在调用方法之前已经完成,则可以同步执行计算,即在调用thenApply
的同一线程中执行。但是,计算也可以由完成未来的线程或在同一CompletableFuture
上调用某个方法的某个其他线程异步执行。答案:https://stackoverflow.com/a/46062939/1235217详细解释了thenApply能做什么和不能保证什么。
那么,您什么时候应该使用thenApply
?什么时候thenApplyAsync
?我使用以下经验法则: