Java多线程之ExecutorCompletionService
创始人
2025-06-01 19:56:24
0

文章目录

  • 1 ExecutorCompletionService
    • 1.1 简介
    • 1.2 原理
    • 1.3 Demo示例
      • 1.3.1 未使用ExecutorCompletionService
      • 1.3.2 使用ExecutorCompletionService
    • 1.4 深入分析说明
      • 1.4.1 所有方法
      • 1.4.2 构造方法
      • 1.4.3 获取方法
      • 1.4.4 提交方法

1 ExecutorCompletionService

1.1 简介

当我们向Executor提交一组任务,并且希望任务在完成后获得结果,此时可以考虑使用ExecutorCompletionService

ExecutorCompletionService实现了CompletionService接口。ExecutorCompletionServiceExecutorBlockingQueue功能融合在一起,使用它可以提交我们的Callable任务。这个任务委托给Executor执行,可以使用ExecutorCompletionService对象的takepoll方法获取结果。

ExecutorCompletionService的设计目的在于提供一个可获取线程池执行结果的功能,这个类采用了装饰器模式,需要用户提供一个自定义的线程池,在ExecutorCompletionService内部持有该线程池进行线程执行,在原有的线程池功能基础上装饰额外的功能。

ExecutorCompletionService 相比之前 Future 相比 ,提供了一个通知机制,将结果统一到一个队列,当前提交任务不会阻塞获取,从另一个队列中阻塞获取。

1.2 原理

在这里插入图片描述

执行原理:

  • 在使用ExecutorCompletionService时需要提供一个自定义的线程池Executor,构造ExecutorCompletionService。同时,也可以指定一个自定义的队列作为线程执行结果的容器,当线程执行完成时,通过重写FutureTask#done()将结果压入队列中。
  • 当用户把所有的任务都提交了以后,可通过ExecutorCompletionService#poll方法来弹出已完成的结果,这样做的好处是可以节省获取完成结果的时间。

1.3 Demo示例

1.3.1 未使用ExecutorCompletionService

public class ExecutorCompletionServiceDemo {public static void main(String[] args) {//这里只是为了方便,真正项目中不要这样创建线程池ExecutorService executorService = Executors.newFixedThreadPool(5);List> list = new ArrayList<>();Future future1 = executorService.submit(() -> {System.out.println("执行任务1开始");try {TimeUnit.SECONDS.sleep(5);} catch (InterruptedException e) {e.printStackTrace();}System.out.println("执行任务1结束");return "任务1执行成功";});list.add(future1);Future future2 = executorService.submit(() -> {System.out.println("执行任务2开始");try {TimeUnit.SECONDS.sleep(3);} catch (InterruptedException e) {e.printStackTrace();}System.out.println("执行任务2结束");return "任务2执行成功";});list.add(future2);Future future3 = executorService.submit(() -> {System.out.println("执行任务3开始");try {TimeUnit.SECONDS.sleep(1);} catch (InterruptedException e) {e.printStackTrace();}System.out.println("执行任务3结束");return "任务3执行成功";});list.add(future3);for (int i = 0; i < list.size(); i++) {String s = null;try {s = list.get(i).get();} catch (InterruptedException e) {e.printStackTrace();} catch (ExecutionException e) {e.printStackTrace();}System.out.println(s);}executorService.shutdown();}
}

在这里插入图片描述

我们可以看到三个任务的执行结果会按照提交顺序的任务执行时间进行堵塞依次获取结果;我们提交到线程池中,通过Futrue类的get()方法,会造成堵塞,需要先等执行任务1的线程结束返回结果,才会进行获取下一个任务的执行的结果,那边后面的任务先于任务一执行结束;当然如果工作中我们不需要获取多个任务执行的结果,我们可以采用上面的实现方式去进行并行处理任务;

1.3.2 使用ExecutorCompletionService

如果我们要获取到并行处理任务的结果快慢来进行一些处理,我们就可以使用到ExecutorCompletionService来进行实现;我们来使用ExecutorCompletionService类将线程池进行包装处理下,然后进行提交任务;

public class ExecutorCompletionServiceDemo {public static void main(String[] args) {//这里只是为了方便,真正项目中不要这样创建线程池ExecutorService executorService = Executors.newFixedThreadPool(5);ExecutorCompletionService completionService = new ExecutorCompletionService<>(executorService);completionService.submit(() -> {System.out.println("执行任务1开始");try {TimeUnit.SECONDS.sleep(5);} catch (InterruptedException e) {e.printStackTrace();}System.out.println("执行任务1结束");return "任务1执行成功";});completionService.submit(() -> {System.out.println("执行任务2开始");try {TimeUnit.SECONDS.sleep(3);} catch (InterruptedException e) {e.printStackTrace();}System.out.println("执行任务2结束");return "任务2执行成功";});completionService.submit(() -> {System.out.println("执行任务3开始");try {TimeUnit.SECONDS.sleep(1);} catch (InterruptedException e) {e.printStackTrace();}System.out.println("执行任务3结束");return "任务3执行成功";});for (int i = 0; i < 3; i++) {try {String result = completionService.take().get();System.out.println(result);} catch (InterruptedException e) {e.printStackTrace();} catch (ExecutionException e) {e.printStackTrace();}}executorService.shutdown();}
}

在这里插入图片描述

1.4 深入分析说明

解决批量提交任务办法就是使用使用 ExecutorCompletionService,异步通知返回。

1.4.1 所有方法

当前类提供的方法
在这里插入图片描述

1.4.2 构造方法

提供的两个构造函数,一个可以指定返回阻塞队列,另一个使用默认的。另外都需要提供一个线程池进来
在这里插入图片描述

1.4.3 获取方法

提供了三个获取方法,可以看到都是从队列中获取
在这里插入图片描述

take获取:谁先执行完 谁先出来 take() 获取时候回阻塞 也可以通过Poll方法获取
polltake 区别在于 poll 可以执行超时时间,可以看到,谁先执行结束 谁先出来。

1.4.4 提交方法

两个提交任务方法
在这里插入图片描述
如何执行任务结果放入队列呢?

可以看到是将 执行结果放入队列中。
内部实现了异步执行接口,以及重写了它的done方法
在这里插入图片描述

相关内容

热门资讯

速腾聚创一季度毛利同比增七成 ...   速腾聚创第二代灵巧手Papert 2.0。  5月30日,速腾聚创发布2025年第一季度财报。据...
“消费+科技”双轮驱动,港股市... 港股IPO市场正经历显著回暖,优质资产供给逐步改善,市场流动性增强,吸引了大量资金关注。Wind资讯...
从一面之恩到千亿帝国CEO,安... 近日,吉利汽车管理层大调整引发行业聚焦。在吉利一季度财报发布的当天,吉利控股集团宣布重大人事调整:极...
A股公司密集更名折射四大现象 ... 据不完全统计,2025年以来,超60家A股公司完成或启动名称变更工作,其中超30家公司涉及证券简称调...
券商6月“金股”出炉,两大行业... A股6月开市在即,券商6月月度“金股”近期陆续出炉。Wind数据显示,截至6月2日中国证券报记者发稿...
朴朴永辉福州“停火” 永辉和朴... 交流朴朴永辉,实名添加微信lihua759321进群在福州前置仓生鲜到家市场,过往的两大主力玩家、总...
美股下跌,钢铁股大涨!金价重回... 6月2日,美国三大股指开盘走低,截至22:40发稿,道指跌0.5%,标普500指数跌0.25%,纳斯...
这个账单,决定后半辈子幸福… ... 图:Hiroki Kawanabe 第一波延迟退休的人出来了。 挺多人晒出来的退休年龄数字,已经有零...
立案调查完毕,香港老板无罪,被... 字越少,事越大,相反,说得越热闹的,往往没啥事儿。84天前,上市公司万辰集团老板王健坤被国家某监委带...
靠卖丸子年入百亿,拿下10万家... 订阅 快刀财经 ▲ 做您的私人商学院一粒鱼丸的逆袭史。作者:朱末来源:快刀财经(ID:kuaidao...
港股数字货币板块集体大涨:连连... 6月2日,港股数字货币板块集体大涨。具体来看,连连数字(02598.HK)一度涨超79%,移卡(09...
“近视神药”跌下神坛,“眼药大... “近视神药”能成为百亿大药吗??作者 | 赵普编辑丨高岩来源 | 野马财经在眼药领域,尤其是备受瞩目...
这届高考,仍是史上最难 史上最... 作者 |暴雨再过几天,我们会迎来历史上最难的一届高考。你可能会反驳,1335万名考生,比去年少了7万...
A股“618”来袭!5月“稳稳... 5月份涨幅排名靠前个股本报(chinatimes.net.cn)记者王兆寰 北京报道5月的A股走出了...
“价格战”影响多大?理想汽车单... 短短两年时间内,不断推迟公布财报披露时间,单车平均净利润不断下滑,理想汽车(02015.HK)给到投...
刚刚,杀出一个医药大白马,挑战... 重重挑战激发无限动力!集采、竞争,仿佛是医药企业头顶的两座大山。连恒瑞医药、华东医药都不免因此出现短...
恒生指数跌0.57%,恒生科技... 6月2日,恒生指数收盘跌0.57%报23157.97点,恒生科技指数跌0.7%,恒生中国企业指数跌0...
银河证券:6月A股大概率震荡上... 展望A股6月运行,银河证券在最新研报中表示,预计市场将大概率震荡上行,建议把握波动中的确定性。银河证...
华仁药业:股东华仁世纪集团拟减... 新京报贝壳财经讯 6月2日,华仁药业(300110.SZ)公告称,公司收到持股5%以上股东华仁世纪集...
冯仑:不被拿捏的关键 冯仑不焦... 封面图 | 《巴斯特·斯克鲁格斯的歌谣》01问:冯叔,我在读您的新书《人生的逻辑》。您在书里说,这本...