为了账号安全,请及时绑定邮箱和手机立即绑定

CompletableFuture 回调将始终执行

CompletableFuture 回调将始终执行

小唯快跑啊 2021-08-25 11:08:30
我有两个服务电话: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();从运行我的示例代码来看,它们似乎都是一样的。但我觉得某处可能有问题。谢谢!
查看完整描述

2 回答

?
牧羊人nacy

TA贡献1862条经验 获得超7个赞

它们不一样。


简而言之,您可以将其视为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) {

    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()是多余的,除非您在两个期货完成之间执行操作


查看完整回答
反对 回复 2021-08-25
?
肥皂起泡泡

TA贡献1829条经验 获得超6个赞

的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完成时结束。这在功能上也应该与第一个相同。


查看完整回答
反对 回复 2021-08-25
  • 2 回答
  • 0 关注
  • 216 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信