一篇文章搞懂 CompletionService
2021/11/10 23:13:09
本文主要是介绍一篇文章搞懂 CompletionService,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!
前言
本文隶属于专栏《100个问题搞定Java并发》,该专栏为笔者原创,引用请注明来源,不足和错误之处请在评论区帮忙指出,谢谢!
本专栏目录结构和参考文献请见100个问题搞定Java并发
正文
WHY
如果向 Executor 提交了一组计算任务,并且希望在计算完成后获得结果,那么可以保留与每个任务关联的 Future ,然后反复使用 get 方法,同时将参数 timeout 指定为 0 ,从而通过轮询来判断任务是否完成。
这种方法虽然可行,但却有些繁琐。
幸运的是,还有一种更好的方法:
完成服务( CompletionService )
WHAT
CompletionService 将 Executor 和 BlockingQueue 的功能融合在一起。
你可以将 Callable 任务提交给它来执行,然后使用类似于队列操作的 take 和 poll 等方法来获得已完成的结果,而这些结果会在完成时将被封装为 Future 。
ExecutorCompletionService 实现了 CompletionService ,并将计算部分委托给一个 Executor。
ExecutorCompletionService 的实现非常简单。
在构造函数中创建一个 BlockingQueue 来保存计算完成的结果。
当计算完成时,调用 Future - Task 中的 done 方法。
当提交某个任务时,该任务将首先包装为一个 QueueingFuture ,这是 Futuretask 的一个子类,然后再改写子类的 done 方法,并将结果放入 BlockingQueue 中。
take 和 poll 方法委托给了 BlockingQueue ,这些方法会在得出结果之前阻塞。
QueueingFuture 源码(JDK8)
/** * FutureTask extension to enqueue upon completion */ private class QueueingFuture extends FutureTask<Void> { QueueingFuture(RunnableFuture<V> task) { super(task, null); this.task = task; } protected void done() { completionQueue.add(task); } private final Future<V> task; }
实战
使用 CompletionService 实现页面渲染器,可以通过 CompletionService 从两个方面来提高页面渲染器的性能:
缩短总运行时间以及提高响应性。
为每一幅图像的下载都创建一个独立任务,并在线程池中执行它们,从而将串行的下载过程转换为并行的过程:这将减少下载所有图像的总时间。
此外,通过从 CompletionService 中获取结果以及使毎张图片在下载完成后立刻显示出来,能使用户获得一个更加动态和更高响应性的用户界面。 如下所示:
public class Renderer { private final ExecutorService executor; Renderer(ExecutorService executor) { this.executor = executor; } void renderPage(CharSequence source) { List<ImageInfo> info = scanForImageInfo(source); CompletionService<ImageData> completionService = new ExecutorCompletionService<>(executor); for (ImageInfo imageInfo : info) { completionService.submit(new Callable<ImageData>() { @Override public ImageData call() throws Exception { return imageInfo.downloadImage(); } }); renderText(source); } try { for (ImageInfo imageInfo : info) { Future<ImageData> future = completionService.take(); ImageData imageData = future.get(); renderImage(imageData); } } catch (InterruptedException e) { Thread.currentThread().interrupt(); } catch (ExecutionException e) { throw new RuntimeException(e); } } }
这篇关于一篇文章搞懂 CompletionService的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!
- 2024-05-29Elasticsearch慢查询日志配置
- 2024-05-29揭秘华为如此多成功项目的产品关键——Charter模板
- 2024-05-29海外IDC业务拓展的7大挑战
- 2024-05-29InLine Chat功能优化对标Github Copilot,CodeGeeX带来更高效、更直观的编程体验!
- 2024-05-29CodeGeeX 智能编程助手 6 项功能升级,在Visual Studio插件市场霸榜2周!
- 2024-05-29AutoMQ 生态集成 Apache Doris
- 2024-05-292024年IDC行业的深度挖掘:机遇、挑战与未来展望
- 2024-05-29五款扩展组件齐发 —— Volcano、Keda、Crane-scheduler 等,邀你体验
- 2024-05-29AutoMQ 对象存储数据高效组织的秘密: Compaction
- 2024-05-29活动预告|来 GIAC 大会听大数据降本利器:AutoMQ 基于云原生重新设计的 Kafka