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

gur*_*gou 3 java concurrency multithreading asynchronous completable-future

我正在学习 CompletableFuture API,有一个例子:

CompletableFuture.completedFuture(url)
                 .thenComposeAsync(this::readPage, executor)
                 .thenApply(this::getImageURLs)
                 .thenApply(this::saveFoundImages)
                 .....
Run Code Online (Sandbox Code Playgroud)

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

Eug*_*ene 5

好的,所以在CompletableFuture. 例如:

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

最后一个手段,这一行动将在执行Executor您传递给它,它是最明显的一个。

所述第二一个装置,其作用在被执行ForkJoinPool

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

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

你需要开始把它分成更小的部分。您需要了解的是,有些线程会完成某个特定的操作CompletableFuture,有些线程会对其执行某些操作,有些线程会链接某些相关的操作。可能,这些都是不同的线程。这就是一切的开始:

  • 如果依赖动作已经链接,则调用的线程将complete是执行该动作的线程。

  • 如果未来已经完成,那么链接动作的线程将执行它。

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

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

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


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

在您的示例中:之后.thenComposeAsync所有以下链式期货也将由执行者完成。

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

 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();
Run Code Online (Sandbox Code Playgroud)

如果您运行它,您将看到的是main实际执行的thenApply,而不是池中的线程。