如果链中的第一个方法是异步的,那么一系列方法调用 (CompletableFuture API) 是否会异步执行?

Will a chain of method calls (CompletableFuture API) execute asynchronously if the first method in a chain is asynchronous?

我正在研究 CompletableFuture API 有一个例子:

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

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

好的,所以CompletableFuture中有3种方法。例如:

  • thenApply()
  • thenApplyAsync(Function)(没有执行者)
  • thenApplyAsync(Function, Executor)(有执行者)

last表示这个动作会在你传给它的Executor执行,也是最明显的

second一个表示动作在ForkJoinPool.

执行

第一个 更有趣。文档使它听起来很简单,通过:

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,有些线程 执行 一些操作,还有是链接 某些相关操作的线程。这些可能都是 不同的 线程。这就是一切的开始:

  • 如果相关操作已经链接,将调用 complete 的线程将成为执行此操作的线程。

  • 如果 future 已经完成,则链接操作的线程将执行它。

由于上述步骤没有线性动作,因此几乎不可能确定 thenApply 将在哪个线程中执行,至少 100% 确定。该操作可以在以下任何一个中执行:

  • 调用complete/completeExceptionally的线程
  • 执行 thenApply
  • 链接的线程
  • 调用join/get的线程

以上任何一种都有可能。如果你真的想要我做了一个相当有趣的,证明了上面的一些事情。


我不是要挑另一个答案,但他提出了一个相当有趣的观点,我在乞讨中也很困惑:

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

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

 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,而不是池中的线程。