将始终执行CompletableFuture回调

问题描述 投票:2回答:2

我有两个服务电话:

String call1() { ... return "ok"; }
void call2(String) { ... }

我知道CompletableFuture回调的基本方法就像

CompletableFuture<Void> future = CompletableFuture
.supplyAsync(() -> call1())
.thenAccept(s -> call2(s));
future.join();

如果我将两个链式的CompletableFutures分开,例如:

CompletableFuture<String> future1 = CompletableFuture.supplyAsync(() -> call1());
CompletableFuture<Void> future2 = future1.thenAccept(s -> call2(s));
future1.join(); // will call2 be executed at this time?

这与在future2上调用join()有什么不同:

CompletableFuture<String> future1 = CompletableFuture.supplyAsync(() -> call1());
CompletableFuture<Void> future2 = future1.thenAccept(s -> call2(s));
future2.join();

如果我在两个期货上都调用join()怎么办?

CompletableFuture<String> future1 = CompletableFuture.supplyAsync(() -> call1());
CompletableFuture<Void> future2 = future1.thenAccept(s -> call2(s));
future1.join();
future2.join();

它们似乎与运行我的示例代码完全相同。但我觉得某处可能出现了问题。谢谢!

java completable-future
2个回答
3
投票

他们不一样。

简而言之,您可以将其视为future1future2持有不同任务的结果(即使future2使用future1的结果,它是一个不同的未来)。

future1.join()将阻止直到() -> call1()结束,而future2的任务将在此之前开始。 future2.join()将等到s -> call2(s)完成。

如果我将两个链式的CompletableFutures分开,例如:

就任务执行而言,这没有任何区别。它既可以是风格问题,也可以仅在您需要单独使用两个未来对象时使用。

如果我在两个期货上都调用join()怎么办?

在这种情况下,调用future1.join()是多余的,因为你在两个.join调用之间没有做任何事情。如果你想在“任务1完成之后和任务2完成之前”执行某些操作,那将是有意义的。 但在这种情况下,调用future2.join()就足够了。


下面的代码片段应该显示其行为:

public static void main(String[] args) {
    CompletableFuture<Void> future1 = CompletableFuture.runAsync(() -> delay());
    CompletableFuture<Void> future2 = future1.thenRun(() -> delay());

    long start = System.currentTimeMillis();

    future1.join();
    System.out.println("Future 1 done. Waiting for future 2: " 
            + (System.currentTimeMillis() - start));

    future2.join();
    System.out.println("Future 2 complete: " 
            + (System.currentTimeMillis() - start));
}

static void delay() {
    try {
        TimeUnit.SECONDS.sleep(5);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
}

实际上,此代码输出:

Future 1 done. Waiting for future 2: 5001
Future 2 complete: 10001

但是当你删除future1.join()时,输出变为:

Future 2 complete: 10001

这只是意味着future1.join()是多余的,除非你在两个期货的完成之间有行动


2
投票

supplyAsyncthenAccept方法应根据文档自动在单独的线程上执行:

使用ForkJoinPool.commonPool()执行没有显式Executor参数的所有异步方法

在您的示例中,唯一的区别是您的线程在继续之前等待不同的事件,因为加入。这是细分:

CompletableFuture<Void> future = CompletableFuture
.supplyAsync(() -> call1())
.thenAccept(s -> call2(s));
future.join();

这将等到call2完成,因为这是thenAccept方法返回的未来。

CompletableFuture<String> future1 = CompletableFuture.supplyAsync(() -> call1());
CompletableFuture<Void> future2 = future1.thenAccept(s -> call2(s));
future1.join(); // will call2 be executed at this time?

这只会等到call1完成并继续前进。 call2仍将被执行。

CompletableFuture<String> future1 = CompletableFuture.supplyAsync(() -> call1());
CompletableFuture<Void> future2 = future1.thenAccept(s -> call2(s));
future2.join();

这与第一个相同。

CompletableFuture<String> future1 = CompletableFuture.supplyAsync(() -> call1());
CompletableFuture<Void> future2 = future1.thenAccept(s -> call2(s));
future1.join();
future2.join();

future1.join()完成时,调用call1结束,然后当future2.join()完成时call2结束。这应该与第一个功能相同。

© www.soinside.com 2019 - 2024. All rights reserved.