ExecutorService与CompletableFuture

时间:2018-09-12 21:04:38

标签: java asynchronous java-8 executorservice completable-future

我一直在尝试实现异步过程,其中父方法调用子方法,而子方法又将调用三个不同的方法。 我希望所有这些过程都是异步完成的,即在子方法中的这三个调用并行执行后,控件应返回到父方法,并继续执行其余部分。

我有这段代码,经过测试可以正常工作。

public ReturnSomething parent(){
    child();
    ...//rest to UI
}

private void child(){
  ExecutorService executorService = Executors.newFixedThreadPool(3);

  Runnable service1 = () -> {
     MyFileService.service1();
  };

  Runnable service2 = () -> {
      MyFileService.service2();
  };

  Runnable service3 = () -> {
      MyFileService.service3();
  };

  executorService.submit(service1);
  executorService.submit(service2);
  executorService.submit(service3);
}

现在,我的领导要我改用这个。

public ReturnSomething parent(){
    child();
    ...//rest to UI
}

private void child(){
    CompletableFuture.supplyAsync(() ->  MyFileService.service1();
    CompletableFuture.supplyAsync(() ->  MyFileService.service2();
    CompletableFuture.supplyAsync(() ->  MyFileService.service3();
}

我知道CompletableFuture是Java 8的新功能,但是第二代码比第一代码好吗? 因为对于ExecutorService,我没有调用“ get()”方法,所以我不会等待aysnc响应。那么,可以请人解释一下有什么区别吗?

4 个答案:

答案 0 :(得分:2)

从功能上讲,这两种方法大致相同:

  • 您提交要执行的任务;
  • 您不必等待结果。

但是,从技术上讲,存在一些细微的差异:

  • 在第二种方法中,您没有指定执行程序,因此它将使用通用的ForkJoinPool。如果您不想这样做,则必须将执行程序作为supplyAsync()的第二个参数传递;
  • CompletableFuture API允许轻松地与thenApply()thenCompose()等链接更多调用。因此,它比Future返回的简单ExecutorService.submit()更灵活;
  • 使用CompletableFuture可以轻松地使用child()从您的return CompletableFuture.allOf(the previously created futures)方法返回未来。

关于可读性,这是一个优先选择的问题,但是,如果您想要等效的代码,则CompletableFuture方法的格式类似后,可能会被认为不太可读。比较:

executorService.submit(MyFileService::service1);
executorService.submit(MyFileService::service2);
executorService.submit(MyFileService::service3);

使用

CompletableFuture.supplyAsync(MyFileService::service1, executorService);
CompletableFuture.supplyAsync(MyFileService::service2, executorService);
CompletableFuture.supplyAsync(MyFileService::service3, executorService);

答案 1 :(得分:1)

两种情况下您都不必等待结果。

第二种方法的优点是减少了样板。这就是runAsync()supplyAsync()的优点。

但是,如果您实际上未返回任何值,则应使用runAsync()

第二种方法还提供了使用CompletableFuture.allOf()等待所有期货的能力。在第一种情况下也不存在。

答案 2 :(得分:0)

首先,后者提高了可读性。其次,我不确定您是否急于每次parent()调用child()时都创建了一个ExecutorService的新实例。(以通用的方式解释您的问题)。

否则,CompletableFuture.supplyAsync返回一种方便的方法来获取对公共共享池的引用,这将减轻您的生活,除非您希望对池中的线程应满足您的请求的方式进行特定的自定义

https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/ForkJoinPool.html#commonPool--

答案 3 :(得分:0)

如果您使用的是 executorservice,请不要忘记在 executor 上调用 shutdown()。您也可以使用 runAsync() 而不是 supplyAsync()。