如果链中的第一个方法是异步的,一连串的方法调用(CompletableFuture API)是否会异步执行? [英] Will a chain of method calls (CompletableFuture API) execute asynchronously if the first method in a chain is asynchronous?

查看:85
本文介绍了如果链中的第一个方法是异步的,一连串的方法调用(CompletableFuture API)是否会异步执行?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在研究CompletableFuture API,并且有一个示例:

I'm studying CompletableFuture API and there is an example:

CompletableFuture.completedFuture(url)
                 .thenComposeAsync(this::readPage, executor)
                 .thenApply(this::getImageURLs)
                 .thenApply(this::saveFoundImages)
                 .....

我有一个问题:如果我将 thenComposeAsync(...)方法作为第一个方法,链中的其他方法是否将在 executor 中执行?我通过了参数,还是应该使用 async 调用其他方法以在特定执行程序中获得异步执行?

I have a question: if I call the thenComposeAsync(...) method as the first one, will the other methods in the chain execute in the executor which I passed through the params, or I should call the other methods using async to get asynchronous execution in a particular executor?

推荐答案

好,因此 CompletableFuture 中有3种方法.例如:

OK, so there are 3 types of methods in CompletableFuture. For example:

  • thenApply()
  • thenApplyAsync(Function)(没有执行程序)
  • thenApplyAsync(Function,Executor)(带有执行器)
  • thenApply()
  • thenApplyAsync(Function) (without an Executor)
  • thenApplyAsync(Function, Executor) (with an Executor)

最后一个 表示此操作将在传递给它的 Executor 中执行,这是最明显的一个.

The last one means that this action will execute in the Executor that you pass to it and it is the most obvious one.

第二个 表示该动作是在 ForkJoinPool 中执行的.

The second one means that the action is executed in the ForkJoinPool.

第一个 有趣得多.该文档通过以下方式听起来很简单

The first one is far more interesting. The documentation makes it sound like it's easy, via:

依赖完成提供的非异步方法的操作可以由完成当前CompletableFuture 的线程执行,也可以由任何其他调用完成的执行者执行方法

Actions supplied for dependent completions of non-async methods may be performed by the thread that completes the current CompletableFuture, or by any other caller of a completion method

您需要开始将其一分为二.您需要了解的是,有一些完成某个特定的 CompletableFuture 的线程,有一些执行的线程,并且有一些线程 chain 某些相关的动作.这些都是潜在的不同线程.这就是一切的开始:

And you need to start bisecting this into smaller pieces. What you need to understand that there are threads that complete a certain CompletableFuture, there are threads that execute some actions on it and there are threads that chain certain dependent actions. Potentially, these are all different threads. And this is where it all begins:

  • 如果相关操作已被链接,则将调用 complete 的线程将是执行此操作的线程.

  • If the dependent action is already chained, the thread that will call complete is going to be the thread that executes this action.

如果将来已经完成,则链接动作的线程将执行该动作.

If the future is already completed, then the thread that chains the action will execute it.

由于上述步骤没有线性动作,因此几乎无法确定您的 thenApply 将在哪个线程中执行,至少有100%的确定性.该动作可以在以下任何一种方式中执行:

Since there is no linear actions on the steps above, it is literally impossible to say for sure in which thread your thenApply will execute, at least with 100% certainty. That action can be executed in any of :

  • 调用 complete/completeExceptionally
  • 的线程
  • 执行 thenApply
  • 链接的线程
  • 调用 join/get
  • 的线程
  • the thread that calls complete/completeExceptionally
  • the thread that does the chaining of thenApply
  • the thread that calls join/get

以上任何一种可能性都是可能的.如果您真的想要我做一个相当有趣的

Any of the above is a possibility. If you really want I made a rather interesting test here, proving some of the things above.

我不想选择其他答案,但是他提出了一个很有趣的观点,我在乞求中也很困惑:

I am not trying to pick on the other answer, but he made a rather interesting point that I was very confused about in the begging too:

在您的示例中:在 .thenComposeAsync 之后,执行者还将完成以下所有链接的期货.

In your example: After .thenComposeAsync also all the following chained futures will get completed by executor.

我们可以很容易地证明这是不正确的:

We can easily prove that this is not correct:

 CompletableFuture<String> future1 = CompletableFuture.completedFuture("a");
 CompletableFuture<String> future2 = future1.thenApplyAsync(x -> "b" + x, Executors.newCachedThreadPool());

 LockSupport.parkNanos(TimeUnit.SECONDS.toNanos(1));

 CompletableFuture<String> future3 = future2.thenApply(x -> {
      System.out.println(Thread.currentThread().getName());
      return x + "c";
 });
 future3.join();

如果运行此命令,您将看到的是 main 实际上执行 thenApply ,而不是池中的线程.

What you are going to see if you run this, is that main actually executes thenApply, not a thread from the pool.

这篇关于如果链中的第一个方法是异步的,一连串的方法调用(CompletableFuture API)是否会异步执行?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆