我一直在尝试实现异步过程,其中父方法调用子方法,而子方法又将调用三个不同的方法。 我希望所有这些过程都是异步完成的,即在子方法中的这三个调用并行执行后,控件应返回到父方法,并继续执行其余部分。
我有这段代码,经过测试可以正常工作。
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响应。那么,可以请人解释一下有什么区别吗?
答案 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()。