本文介绍了如果链中的第一个方法是异步的,那么一系列方法调用 (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)

last 表示此操作将在您传递给它的 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 first one is far more interesting. The documentation makes it sound like it's easy, via:

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

你需要开始把它分成更小的部分.您需要了解的是,有些线程完成某个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
  • 的线程

以上任何一种都是可能的.如果你真的想要我做了一个相当有趣的 在这里测试,证明上面的一些事情.

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 之后,所有以下链式期货也将由执行程序完成.

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

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) 是否会异步执行?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

05-18 20:58