最近使用多线程优化了一个非常耗时的ping任务,下面的是未优化的源代码,大致就是遍历es取出的list,然后循环判断是否能ping通:

SearchResponse searchResponse = client.search(searchRequest);
Iterator it = searchResponse.getHits().iterator();
while (it.hasNext()) {boolean isReachAble = false;SearchHit hit = (SearchHit) it.next();Link link = new Link();Map<String, Object> map = hit.getSourceAsMap();String area = (String) map.get("area");if ("上海".equals(area)) {//过滤掉上海地区continue;}List<String> getways = (List<String>) map.get("gateway");//一旦能连通其中任一网关则代表连接成功for (String getway : getways) {//这个isIpReachable很耗时if (isIpReachable(getway)) {isReachAble = true;break;}}link.setArea(area);link.setIsLink(isReachAble ? 1 : 0);links.add(link);
}

多线程的话现在基本都是直接使用线程池了吧,如下面第一行代码就能创建一个线程数为4的线程池:

ExecutorService executorService = Executors.newFixedThreadPool(4);
CompletionService<String> pool = new ExecutorCompletionService<String>(executorService);

第二行的这个CompletionService是我们今天介绍的重点,它与默认的ExecutorService的最大区别就是:

通过executorService来submit的task不一定是按照加入自己维护的list顺序完成的;从list中遍历的每个Future对象并不一定处于完成状态,这时调用get()方法就会被阻塞住,如果系统是设计成每个线程完成后就能根据其结果继续做后面的事,这样对于处于list后面的但是先完成的线程就会增加了额外的等待时间。

而CompletionService的实现是维护一个保存Future对象的BlockingQueue。只有当这个Future对象状态是结束的时候,才会加入到这个Queue中,take()方法其实就是Producer-Consumer中的Consumer。它会从Queue中取出Future对象,如果Queue是空的,就会阻塞在那里,直到有完成的Future对象加入到Queue中。

所以,先完成的必定先被取出。这样就减少了不必要的等待时间

好了废话不多说,直接上优化后的代码:

//response中包含从es中取到的数据
SearchResponse searchResponse = client.search(searchRequest);
Iterator it = searchResponse.getHits().iterator();//创建固定数目线程的线程池
ExecutorService executorService = Executors.newFixedThreadPool(4);
CompletionService<String> pool = new ExecutorCompletionService<String>(executorService);
List<Future<String>> resultList = new ArrayList<>();
while (it.hasNext()) {SearchHit hit = (SearchHit) it.next();Map<String, Object> map = hit.getSourceAsMap();List<String> getways = (List<String>) map.get("gateway");String area = (String) map.get("area");if ("上海".equals(area)) {//过滤掉上海地区continue;}//将耗时任务submit到线程池中resultList.add(pool.submit(() -> {long t1 = System.currentTimeMillis();boolean isReachAble = false;Link link = new Link();//一旦能连通其中任一网关则代表连接成功for (String getway : getways) {if (isIpReachable(getway)) {isReachAble = true;break;}}link.setArea((String) map.get("area"));link.setIsLink(isReachAble ? 1 : 0);links.add(link);long t2 = System.currentTimeMillis();return "task " + map.get("area") + " completed.耗时:" + (t2 - t1);}));
}
//如果没有下面的代码,主线程将直接返回
for(int i = 0; i < resultList.size(); i++){//在取到数据之前将会一直阻塞String result = pool.take().get();System.out.println(result);
}

我特地将单线程和多线程运行结果做了个对比,可以看到多线程优化过后时间减了一半之多

下面的是控制台输出,发现执行顺序确实基本是按时间由短到长,正好体现出了CompletionService的优点

JDK线程池CompletionService的使用相关推荐

  1. JDK线程池的ThreadFactory

    JDK线程池:Executors.newFixedThreadPool , Executors.newSingleThreadExecutor,由一个ThreadFactory来创建新的线程,默认情况 ...

  2. 一个JDK线程池BUG引发的GC机制思考

    点击上方"方志朋",选择"设为星标" 回复"666"获取新整理的面试资料 作者:空无 来源:https://urlify.cn/63QrYv ...

  3. juc线程池原理(六):jdk线程池中的设计模式

    一.jdk中默认线程池中的代理模式 单例类线程池只有一个线程,无边界队列,适合cpu密集的运算.jdk中创建线程池是通过Executors类中提供的静态的方法来创建的,其中的单例类线程池的方法如下: ...

  4. 深入剖析JDK线程池ThreadPool

    前言 线程池是java人员在工作中经遇到的一个技术,也是一个技术难点,最近遇到一个生产环境线程池使用问题,今天特针对源码和平时的工作经验,对ThreadPoolExecutor进行一个全面的剖析 1. ...

  5. 突然就懵了!面试官问我:线程池中多余的线程是如何回收的?

    点击关注公众号,Java干货及时送达 最近阅读了JDK线程池ThreadPoolExecutor的源码,对线程池执行任务的流程有了大体了解,实际上这个流程也十分通俗易懂,就不再赘述了,别人写的比我好多 ...

  6. 由于不知线程池的bug,某Java程序员叕被祭天

    说说你对线程池的理解? 首先明确,池化的意义在于缓存,创建性能开销较大的对象,比如线程池.连接池.内存池.预先在池里创建一些对象,使用时直接取,用完就归还复用,使用策略调整池中缓存对象的数量. Jav ...

  7. Java线程池实现原理及其在美团业务中的实践

    来自:美团技术团队 随着计算机行业的飞速发展,摩尔定律逐渐失效,多核CPU成为主流.使用多线程并行计算逐渐成为开发人员提升服务器性能的基本武器.J.U.C提供的线程池ThreadPoolExecuto ...

  8. 手把手教你手动创建线程池

    点击上方 好好学java ,选择 星标 公众号 重磅资讯.干货,第一时间送达 今日推荐:2020,搞个 Mac 玩玩!个人原创+1博客:点击前往,查看更多 作者:IamHYN 链接:https://s ...

  9. 面试官问:你做过什么Java线程池实践,我写了一篇博客给他看~

    线程池大家都## 标题很熟悉,无论是平时的业务开发还是框架中间件都会用到,大部分都是基于JDK线程池ThreadPoolExecutor做的封装, 都会牵涉到这几个核心参数的设置:核心线程数,等待(任 ...

最新文章

  1. 【css】页面出现两个滚动条以及只有一半页面显示内容的解决方法
  2. POJ 1144 Network (求割点)
  3. 我的申请总结~好像创业公司啊
  4. QT乱码总结8.编码测试和总结三
  5. python面试题_17道Python面试题,分享给你以防不测!
  6. 【C#】带等待窗体的BackgroundWorker
  7. artcam 9.0英文版本下载_Jenkins版本升级(修复漏洞)
  8. string返回第n个字符_Programming in Lualua学习第13期 Lua字符串库
  9. Spark-TaskSchedule和TaskScheduleImpl解释和过程
  10. Quartz 触发器、过期触发策略 、排它日历、数据持久化
  11. windows如何更改字体
  12. 【JAVA】java获取项目地址或tomcat绝对地址
  13. Java、对字符串中的字符排序
  14. 【Excel 操作】二维表转一维表的两种方法
  15. arm9开发板学习笔记之程序烧录
  16. 总结HTMLT5高级的新特性
  17. 什么是DBMS,什么是数据库?
  18. Android实现实时视频聊天功能|源码 Demo 分享
  19. 反对称矩阵乘任意矩阵满足交换性?
  20. || ?? 和 ?. 的意思

热门文章

  1. 青海师大c语言研究生专业课,2016年青海师范大学计算机应用技术C语言程序设计考研复试题库...
  2. 下拉推广系统立择火星推荐_下拉词删除都择火星下拉
  3. 印象笔记编辑pdf_笔记软件使用体验(至2020.03)
  4. 底层实现红黑树_图解:红黑树
  5. 永不休眠怎么设置_电脑休眠后应该怎样唤醒?
  6. java scanner_Java Scanner radix()方法与示例
  7. python线程任务run_Python线程类| 带有示例的run()方法
  8. 建立单链表 单链表的插入_单链列表插入
  9. pythonweb自动化测试实例_[转载]python webdriver自动化测试实例
  10. rgb 灰色_金属+RGB+无线,我要买爆这款海盗船VIRTUOSO鉴赏家游戏耳机