2017-11-25 23 views
3

假设我有以下代码:然后应用程序和Java CompletableFuture的应用程序同步有什么区别?

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在一个单独的线程中执行,并'在同一时间'(这意味着下面的thenApplyAsyncs开始之前thenApplyAsyncs完成),如果是这样,如果第一步没有完成,第二步的输入参数值是什么?

如果第二步不采取第一步的结果,那么第二步的结果将在哪里结束? 第三步将采取哪一步的结果?

如果第二步需要等待第一步的结果,那么Async的要点是什么?

这里x - > x + 1只是为了表明这一点,我想知道的是在计算时间很长的情况下。

+0

你在IDE调试器中试过这个吗?似乎你可以很容易地找出几个恰当的断点发生的事情。 –

+0

有趣的问题!我在文本中添加了一些格式,我希望没问题。请注意,您可以使用内嵌代码的“'”将其格式化为代码,并且您需要一个空行来创建新段落。 – Lii

+0

除了'thenApply'的情况,我对并发性并不熟悉,并没有太多实践,我的天真印象是并发代码难以跟踪,所以不要尝试自己,我希望有人可以给我为此澄清了我的困惑。 @JimGarrison – Yulin

回答

3

不同之处在于负责运行代码的ExecutorCompletableFuture上的每个运营商通常有3个版本。

  1. thenApply(fn) - 运行fn上通过调用它的CompleteableFuture定义一个线程,所以你一般不能知道这会被执行。如果结果已经可用,它可能立即执行。
  2. thenApplyAsync(fn) - 在环境定义的执行器上运行fn,无论情况如何。对于CompletableFuture,这通常是ForkJoinPool.commonPool()
  3. thenApplyAsync(fn,exec) - 在exec上运行fn

最后结果是一样的,但调度行为取决于方法的选择。

+0

不错的回答,很好的解释'thenApply'的所有差异版本。但我想你错过了这个问题的这一部分:“有什么意义?”何时以及为什么要使用'thenApplyAsync'而不是'thenApply'?他们会同时运行,不是吗?差异似乎只是在他们运行的线程上,但这应该没什么关系,因为无论如何它们都可能在某个线程池线程上运行。 – Lii

+1

这是一个链条,链条中的每个呼叫都取决于前一部分的完成。如果需要在预定义的执行程序上执行该功能,则使用'thenApplyAsync'。处理UI更新作为对未来结果的响应时,会在UI线程上执行一个示例。 – Kiskae

+0

与'thenApply'相比,'thenApplyAsync'是否不会阻止当前线程并且在其他方​​面没有区别?假设任务非常昂贵。 – Yulin

0

这是文件说怎么样CompletableFuture'sthenApplyAsync

返回,当这一阶段完成 常新CompletionStage,使用此阶段的默认异步 执行机构执行,这个阶段的结果作为提供了 提供的功能。

所以,thenApplyAsync必须等待前面的thenApplyAsync's结果:

在你的情况,你首先做同步工作,然后异步之一。所以,第二个是异步的并不重要,因为它只在同步工作完成后才启动。

让我们切换它。在某些情况下,首先打印“异步结果:2”,在某些情况下,首先打印“同步结果:2”。这里有所不同,因为调用1和2都可以异步运行,在单独的线程上调用1,并在其他线程(可能是主线程)上调用2。

CompletableFuture<Integer> future 
       = CompletableFuture.supplyAsync(() -> 0); 

future.thenApplyAsync(x -> x + 1) // call 1 
       .thenApplyAsync(x -> x + 1) 
       .thenAccept(x -> System.out.println("async result: " + x)); 

future.thenApply(x -> x + 1) // call 2 
       .thenApply(x -> x + 1) 
       .thenAccept(x -> System.out.println("sync result:" + x)); 
+1

在主线程或其他线程上执行“调用2”是否取决于“future”的状态。如果它已经有结果,那么它将在主线程上执行。否则,它将注册一个回调,并在'supplyAsync'的结果可用于任何可能的线程时执行。 – Kiskae

+0

@Kiskae true,thank you –

相关问题