【问题标题】:Will a chain of method calls (CompletableFuture API) execute asynchronously if the first method in a chain is asynchronous?如果链中的第一个方法是异步的,则方法调用链(CompletableFuture API)是否会异步执行?
【发布时间】:2021-01-12 14:17:04
【问题描述】:

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

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

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

【问题讨论】:

    标签: java multithreading asynchronous concurrency completable-future


    【解决方案1】:

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

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

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

    一表示动作在ForkJoinPool中执行。

    第一个要有趣得多。文档让它听起来很简单,通过:

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

    您需要开始将其分成更小的部分。您需要了解的是,有些线程完成某个CompletableFuture,有些线程执行一些操作,有些线程链 某些相关的操作。潜在地,这些都是不同的线程。这就是一切的开始:

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

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

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

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

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


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

    在您的示例中:在.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();
    

    如果你运行这个,你会看到main实际上执行thenApply,而不是池中的线程。

    【讨论】:

    • @Holger 谢谢。你认为这样更好吗?
    • 我想,第二个项目符号“如果动作已经完成……”应该意味着“如果未来已经完成”。还值得注意的是,如果完成和动作链接之间存在竞争,甚至可能会产生更令人惊讶的结果(尤其是两个以上的线程)。但是,是的,现在好多了。
    猜你喜欢
    • 2018-05-15
    • 1970-01-01
    • 1970-01-01
    • 2016-12-26
    • 2013-12-15
    • 1970-01-01
    • 2014-09-13
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多