猿问

CompletableFuture 回调将始终执行

我有两个服务电话:


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

void call2(String) { ... }

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


CompletableFuture<Void> future = CompletableFuture

.supplyAsync(() -> call1())

.thenAccept(s -> call2(s));

future.join();

如果我将两个链接的 CompletableFuture 分开会怎样,例如:


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();

从运行我的示例代码来看,它们似乎都是一样的。但我觉得某处可能有问题。谢谢!


小唯快跑啊
浏览 224回答 2
2回答

牧羊人nacy

它们不一样。简而言之,您可以将其视为future1并future2保存不同任务future2的结果(即使使用 的结果future1,也是不同的未来)。future1.join()将阻塞直到() -> call1()结束,并且future2直到那时才开始任务。future2.join()将等到s -> call2(s)完成。如果我将两个链接的 CompletableFuture 分开会怎样,例如:就任务执行而言,这没有区别。这要么是风格问题,要么仅在您需要分别使用两个未来对象时才重要。如果我在两个期货上都调用 join() 怎么办?在这种情况下调用future1.join()是多余的,因为您在两次.join调用之间没有做任何事情。如果您想在“完成任务 1 之后和完成任务 2 之前”执行某些操作,那将是有意义的。不过,在这种情况下,调用future2.join()就足够了。下面的代码片段应显示其行为方式:public static void main(String[] args) {&nbsp; &nbsp; CompletableFuture<Void> future1 = CompletableFuture.runAsync(() -> delay());&nbsp; &nbsp; CompletableFuture<Void> future2 = future1.thenRun(() -> delay());&nbsp; &nbsp; long start = System.currentTimeMillis();&nbsp; &nbsp; future1.join();&nbsp; &nbsp; System.out.println("Future 1 done. Waiting for future 2: "&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; + (System.currentTimeMillis() - start));&nbsp; &nbsp; future2.join();&nbsp; &nbsp; System.out.println("Future 2 complete: "&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; + (System.currentTimeMillis() - start));}static void delay() {&nbsp; &nbsp; try {&nbsp; &nbsp; &nbsp; &nbsp; TimeUnit.SECONDS.sleep(5);&nbsp; &nbsp; } catch (InterruptedException e) {&nbsp; &nbsp; &nbsp; &nbsp; e.printStackTrace();&nbsp; &nbsp; }}照原样,此代码输出:Future 1 done. Waiting for future 2: 5001Future 2 complete: 10001但是当你删除时future1.join(),输出变成:Future 2 complete: 10001这只是意味着这future1.join()是多余的,除非您在两个期货完成之间执行操作

肥皂起泡泡

的supplyAsync和thenAccept方法应在一个单独的线程自动根据文档执行:所有没有显式 Executor 参数的异步方法都使用 ForkJoinPool.commonPool() 执行在您的示例中,唯一的区别是您的线程在由于加入而继续之前等待不同的事件。这是细分: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完成时结束。这在功能上也应该与第一个相同。
随时随地看视频慕课网APP

相关分类

Java
我要回答