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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/47489338/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-11-03 09:38:45  来源:igfitidea点击:

What is the difference between thenApply and thenApplyAsync of Java CompletableFuture?

javacompletable-future

提问by Yulin

Suppose I have the following code:

假设我有以下代码:

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

thenApplycase:

thenApply案件:

future.thenApply( x -> x + 1 )
      .thenApply( x -> x + 1 )
      .thenAccept( x -> System.out.println(x));

Here the output will be 2. Now in case of thenApplyAsync:

这里的输出将为 2。现在在以下情况下thenApplyAsync

future.thenApplyAsync( x -> x + 1 )   // first step
      .thenApplyAsync( x -> x + 1 )   // second step
      .thenAccept( x -> System.out.println(x)); // third step

I read in this blogthat each thenApplyAsyncare executed in a separate thread and 'at the same time'(that means following thenApplyAsyncsstarted before preceding thenApplyAsyncsfinish), if so, what is the input argument value of the second step if the first step not finished?

我在这篇博客中读到,每个thenApplyAsync都在一个单独的线程中执行,并且“同时”执行(这意味着thenApplyAsyncsthenApplyAsyncs完成之前开始跟随),如果是这样,如果第一步没有完成,第二步的输入参数值是多少?

Where will the result of the first step go if not taken by the second step? the third step will take which step's result?

如果不采取第二步,第一步的结果将何去何从?第三步会走哪一步的结果?

If the second step has to wait for the result of the first step then what is the point of Async?

如果第二步必须等待第一步的结果,那还有什么意义Async呢?

Here x -> x + 1 is just to show the point, what I want know is in cases of very long computation.

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

采纳答案by Kiskae

The difference has to do with the Executorthat is responsible for running the code. Each operator on CompletableFuturegenerally has 3 versions.

区别Executor在于负责运行代码的那个。每个算子上CompletableFuture一般有3个版本。

  1. thenApply(fn)- runs fnon a thread defined by the CompleteableFutureon which it is called, so you generally cannot know where this will be executed. It might immediately execute if the result is already available.
  2. thenApplyAsync(fn)- runs fnon a environment-defined executor regardless of circumstances. For CompletableFuturethis will generally be ForkJoinPool.commonPool().
  3. thenApplyAsync(fn,exec)- runs fnon exec.
  1. thenApply(fn)-fn在由CompleteableFuture调用它的定义的线程上运行,因此您通常不知道它将在哪里执行。如果结果已经可用,它可能会立即执行。
  2. thenApplyAsync(fn)-fn无论情况如何,都在环境定义的执行程序上运行。对于CompletableFuture这通常会ForkJoinPool.commonPool()
  3. thenApplyAsync(fn,exec)-运行fnexec

In the end the result is the same, but the scheduling behavior depends on the choice of method.

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

回答by 1283822

You're misunderstanding the examples you quoted. In both examples, the second function has to wait for the first function to complete. Whenever you call a.then___(b -> ...), input bis the result of aand has to wait for ato complete, regardless of whether you use Async or not.

你误解了你引用的例子。在这两个示例中,第二个函数必须等待第一个函数完成。无论何时调用a.then___(b -> ...),输入b都是 的结果a并且必须等待a完成,无论您是否使用 Async。

The actual example in the article is

文章中的实际例子是

CompletableFuture<String> receiver = CompletableFuture.supplyAsync(this::findReceiver);

receiver.thenApplyAsync(this::sendMsg);  
receiver.thenApplyAsync(this::sendMsg);  

Notice the thenApplyAsyncboth applied on receiver, not chained in the same statement. This means both function can start once receivercompletes, in an unspecified order. (Any assumption of order is implementation dependent.)

注意thenApplyAsync两者都应用于receiver,而不是链接在同一个语句中。这意味着两个函数都可以在receiver完成后以未指定的顺序启动。(任何顺序假设都取决于实现。)



More technical explanation

更多技术说明

I must point out that thenApplyand thenApplyAsyncare terribly named and are confusing to the unfamiliar. There is nothing in thenApplyAsyncthat is more asynchronous than thenApplyfrom the contract of these methods.

我必须指出,thenApplythenApplyAsync被命名的可怕和感到困惑的陌生。没有什么thenApplyAsyncthenApply这些方法的契约更异步的了。

The difference between the two has to do with on which thread the function is run. The function supplied to thenApplymay run on any of the threadsthat

两者之间的区别与函数在哪个线程上运行有关。提供给函数thenApply可以在任何线程运行

  1. call complete
  2. call thenApplyon the same instance
  1. 称呼 complete
  2. 调用thenApply同一个实例

while thenApplyAsynceither uses a default Executor(a.k.a. thread pool), or a supplied Executor.

whilethenApplyAsync要么使用默认值Executor(又名线程池),要么使用提供的Executor.

Asynchrony != threads

异步 != 线程

thenApply/thenApplyAsync, and their counterparts thenCompose/thenComposeAsync, handle/handleAsync, thenAccept/thenAcceptAsync, are all asynchronous! The asynchronous nature of these function has to do with the fact that an asynchronous operation eventuallycalls completeor completeExceptionally. The idea came from Javascript, which is indeed asynchronous but isn't multi-threaded.

thenApply/ thenApplyAsync,和它们对应的thenCompose/ thenComposeAsynchandle/ handleAsyncthenAccept/ thenAcceptAsync,都是异步的!这些函数的异步特性与异步操作最终调用complete或的事实有关completeExceptionally。这个想法来自 Javascript,它确实是异步的,但不是多线程的。

回答by Willi Mentzel

This is what the documentation says about CompletableFuture'sthenApplyAsync:

这是文档所说的内容CompletableFuture'sthenApplyAsync

Returns a new CompletionStage that, when this stage completes normally, is executed using this stage's default asynchronous execution facility, with this stage's result as the argument to the supplied function.

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

So, thenApplyAsynchas to wait for the previous thenApplyAsync'sresult:

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

In your case you first do the synchronous work and then the asynchronous one. So, it does not matter that the second one is asynchronous because it is started only after the synchrounous work has finished.

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

Let's switch it up. In some cases "async result: 2" will be printed first and in some cases "sync result: 2" will be printed first. Here it makes a difference because both call 1 and 2 can run asynchronously, call 1 on a separate thread and call 2 on some other thread, which might be the main thread.

让我们切换它。在某些情况下,“async result: 2”将首先打印,而在某些情况下,“sync result: 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));

回答by Stefan Feuerhahn

The second step (i.e. computation) will always be executed after the first step.

第二步(即计算)将始终在第一步之后执行。

If the second step has to wait for the result of the first step then what is the point of Async?

如果第二步必须等待第一步的结果,那么 Async 的意义何在?

Async means in this case that you are guaranteed that the method will return quickly and the computation will be executed in a different thread.

在这种情况下,异步意味着您可以保证该方法将快速返回并且计算将在不同的线程中执行。

When calling thenApply(without async), then you have no such guarantee. In this case the computation may be executed synchronously i.e. in the same thread that calls thenApplyif the CompletableFuture is already completed by the time the method is called. But the computation may also be executed asynchronously by the thread that completes the future or some other thread that calls a method on the same CompletableFuture. This answer: https://stackoverflow.com/a/46062939/1235217explained in detail what thenApply does and does not guarantee.

当调用thenApply(没有异步)时,你就没有这样的保证。在这种情况下,计算可以同步执行,即thenApply如果 CompletableFuture 在调用方法时已经完成,则在调用的同一线程中执行。但是计算也可以由完成 future 的线程或调用相同CompletableFuture.方法的其他线程异步执行。这个答案:https: //stackoverflow.com/a/46062939/1235217 详细解释了 thenApply 做什么和不保证什么。

So when should you use thenApplyand when thenApplyAsync? I use the following rule of thumb:

那么什么时候应该使用thenApply,什么时候使用thenApplyAsync?我使用以下经验法则:

  • non-async: only if the task is very small and non-blocking, because in this case we don't care which of the possible threads executes it
  • async (often with an explicit executor as parameter): for all other tasks
  • 非异步:仅当任务非常小且非阻塞时,因为在这种情况下我们不关心哪个可能的线程执行它
  • 异步(通常以显式执行器作为参数):用于所有其他任务