Java CompletableFuture的thenApply和thenApplyAsync有什么区别?

假设我有以下代码:

CompletableFuture 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 

我在这篇博客中读到,每个thenApplyAsync都是在一个单独的线程中执行的,并且“同时”(这意味着在执行thenApplyAsyncs之前,然后启动了thenApplyAsyncs ),如果是这样的话,如果是第一步,第二步的输入参数值是多少没做完?

如果不是第二步,第一步的结果会在哪里? 第三步将采取哪一步的结果?

如果第二步必须等待第一步的结果那么Async的重点是什么?

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

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

  1. thenApply(fn) – 在调用它的CompleteableFuture定义的线程上运行fn ,因此通常无法知道它将在何处执行。 如果结果已经可用,它可能会立即执行。
  2. thenApplyAsync(fn) – 在环境定义的执行程序上运行fn ,无论情况如何。 对于CompletableFuture这通常是ForkJoinPool.commonPool()
  3. thenApplyAsync(fn,exec) – 在exec上运行fn

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

这就是文档中有关CompletableFuture's thenApplyAsync

返回一个新的CompletionStage,当该阶段正常完成时,使用此阶段的默认异步执行工具执行,该阶段的结果作为所提供函数的参数。

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

在您的情况下,您首先执行同步工作,然后执行异步工作。 因此,第二个是异步的并不重要,因为它只在同步工作完成后启动。

我们把它换掉吧。 在某些情况下,将首先打印“异步结果:2”,在某些情况下,将首先打印“同步结果:2”。 这里有所不同,因为调用1和2都可以异步运行,在一个单独的线程上调用1,在另一个线程上调用2,这可能是主线程。

 CompletableFuture 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)); 

我必须指出,名称thenApply然后应用thenApplyAsync是绝对可怕和令人困惑的。 thenApplyAsync中没有任何内容比这些方法的契约中的thenApply更异步。

差异与运行函数的线程有关。 提供给thenApply的函数可以在任何线程上运行

  1. 通话complete
  2. 在同一个实例上调用thenApply

thenApplyAsync要么使用默认的Executor (也称为。线程池),要么使用提供的Executor

这些函数的异步部分与异步操作最终调用completecompleteExceptionally的事实有关。 这个想法来自Javascript,它与multithreading无关。