我有两个服务电话:
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();
它们似乎与运行我的示例代码完全相同。但我觉得某处可能出现了问题。谢谢!
他们不一样。
简而言之,您可以将其视为future1
和future2
持有不同任务的结果(即使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()
是多余的,除非你在两个期货的完成之间有行动
supplyAsync
和thenAccept
方法应根据文档自动在单独的线程上执行:
使用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
结束。这应该与第一个功能相同。