JDK线程池CompletionService的使用

最近使用多线程优化了一个非常耗时的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的优点

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/553696.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

解决mediawiki上传文件文件名是中文上传失败

公司内部的wiki是用的mediawiki&#xff0c;其它都还好就是上传文件时文件名中有中文就不能上传&#xff0c;这次下决心要修复这个问题&#xff0c;一开始我还以为是哪里需要配置一下&#xff0c;然后搜了半天发现这是一个官方的bug&#xff1a; 好吧&#xff0c;是官方bug也好…

Metricbeat添加ip address信息

Metricbeat默认输出信息里没有ip地址&#xff0c;6.3版本之后可以通过add_host_metadata 来开启附带ip信息&#xff08;没测试过&#xff09; 原本我是通过修改modules.d/system.yml文件&#xff0c;在每项后面加自定义fields.ip字段来添加ip信息&#xff0c;类似下面这样&…

前端获取不了rest请求自定义headers的问题

前端response中的自定义header信息默认同一域中可见 在crossdomain跨域情况下需要在服务器端增加Access-Control-Expose-Headers的支持 例如在springboot中需要使用addExposedHeader添加指定返回头&#xff1a; Configuration public class CORSConfiguration implements WebM…

如何右键文件夹以Sublime 打开

最近总是拖动文件在Sublime Text 的运行环境下&#xff0c;想着能否鼠标右键打开项目文件夹。以下是具体操作步骤 1 windows下打开运行(或者在windowr); 2 输入regedit 进入window配置列表里面 3 在注册表编辑器中找的这个节点&#xff1a;在 HKEY_CLASSSES_ROOT→Folder ll…

高性能网站建设指南

进行优化前&#xff0c;关键是剖析当前的web性能&#xff0c;找到性能瓶颈&#xff0c;从而确定最需改进的地方;如果精力有限&#xff0c;首先将精力放在能明显提升性能的改进点上; 《高性能网站建设指南》提出了一个性能黄金法则&#xff1a; 只有10%-20%的最终用户响应时间花…

js来读写cookie操作

因为之前公司的项目前后端是在一起的&#xff0c;因为要用vue来重构之前的项目。所以token签名要作为一个参数传递到后台。所以就遇到两个问题,1 token的保存和获取的问题。 2 token 判断。判断用户是否用token值。 首先先说一下 token的保存和获取问题。 保存到哪&#xff1…

MUI tab选项卡之间的切换和数据获取

查看mui官网上面的例子&#xff0c;会看到有多种tab 选项卡的例子&#xff0c;我就写下我用到的tab选项卡。写了个简单的例子&#xff0c;效果如下图 主页面的代码 <nav class"mui-bar mui-bar-tab"><a class"mui-tab-item mui-active" href"…

ECharts 联动效果

在使用ECharts 时候要用到联动的&#xff0c;比如下面的示例图&#xff0c;当鼠标经过A的图的时候&#xff0c;这个时候有提示&#xff0c;然后让B的提示也显示出来。这样一个效果。 官方文档给的配置项&#xff0c; http://echarts.baidu.com/api.html#echarts.connect var my…

Git Permission to fazhiyun86/Test.git denied to MarRoar

先说明问题。在我的电脑上有两个SSH key&#xff0c;也就是有两个GitHub账户。我们在GitHub账户里面配置好 SSH key 的时候&#xff0c;就可以向自己的GitHub账户的仓库里面push 代码。 我们先在第一个账户push 代码的时候会让输入 用户名和密码。当向另一个账户push 东西的时…

ECharts 饼图 legend 样式修改

在移动端展示一个数据很多的饼图的时候&#xff0c;首先看一下效果。ECharts legend 配置项 1 legend 让它在右面竖着显示。 legend: {type: scroll,orient: vertical,show: true,right: 0,top: 20,bottom: 20,textStyle: {fontSize: 7},formatter: function (name) {return (n…

ECharts 仪表盘的轴线宽度修改

今天修改仪表盘的轴线宽度&#xff0c; 配置项链接。修改的是下图中线框标注地方的宽度。 下面看一下配置项 option {tooltip : {formatter: "{a} <br/>{b} : {c}%"},toolbox: {feature: {restore: {},saveAsImage: {}}},series: [{name: 业务指标,type: gau…

CSS 让数字滑动显示

最近在做一个数据展示的页面&#xff0c;老板想要的效果是数字滑动的显示。 所以想了一下实现了老板想要的效果。代码如下。 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><title>number</title><…

Status Code:200 OK (from disk cache)和304的区别,以及怎么禁止缓存

有时候缓存是 200 OK (from disk cache)有时候会是 304 ? 看运维是否移除了 Entity Tag。移除了&#xff0c;就总是 200 OK (from cache)。没有移除&#xff0c;就两者交替出现。 他们两个的区别是 200 OK (from disk cache) 是浏览器没有跟服务器确认&#xff0c; 就是它直接…

js 排序

冒泡排序 var dataStore [ 72 , 1 , 68 , 95 , 75 , 54 , 58 , 10 , 35 , 6 , 28 , 45 , 69 , 13 , 88 , 99 , 24 , 28 , 30 , 31 , 78 , 2 , 77 , 82 , 72 ];var t bubbleSort(dataStore);console.log(t);function bubbleSort(data) {var temp 0;for (var i 0; i < dat…

js 类型判断

说到js的类型判断很容易想到的是 typeof、instanceof等。 typeof 有个缺点就是引用类型的结果值都是object 所以就要说一下这些类型是怎么判断的。在说类型判断之前先介绍个东西 Object.prototype.toString 可以查看链接 翻译过来就是 当 toString 方法被调用的时候&#xf…

cordova报错“No installed build tools found. Install the Android build tools version - ”

在cordova 里面添加一个安卓平台后&#xff0c;用android studio打开安装gradle后&#xff0c;然后开始构建项目&#xff0c;这个时候在控制台上会报错 这个时候看到对应的文件下报错信息。 然后我们打开这个文件后&#xff0c; 发现这个 if else 判断走了 else 里面的代码&a…

Vim 常用命令总结

vi 命令编辑器有三种模式&#xff1a;命令模式&#xff0c;编辑模式和末行模式。 命令模式&#xff1a;键盘的任意一个键都可以当成“编辑命令”。 编辑模式&#xff1a;键盘的任意一个键都当成“文本内容”。 末行模式&#xff1a;键盘的任意一个键都当成“文本管理命令”。…

Python数据结构与算法(四)--顺序表

顺序表 在程序中&#xff0c;经常需要将一组&#xff08;通常是同为某个类型的&#xff09;数据元素作为整体管理和使用&#xff0c;需要创建这种元素组&#xff0c;用变量记录它们&#xff0c;传进传出函数等。一组数据中包含的元素个数可能发生变化&#xff08;可以增加或删…

Python数据结构与算法(五)--链表

链表 链表的定义: 链表&#xff08;Linked list&#xff09;是一种常见的基础数据结构&#xff0c;是一种线性表&#xff0c;但是不像顺序表一样连续存储数据&#xff0c;而是在每一个节点&#xff08;数据存储单元&#xff09;里存放下一个节点的位置信息&#xff08;即地址…

Python数据结构与算法(六)--栈和队列

栈和队列 栈&#xff08;stack&#xff09;&#xff0c;有些地方称为堆栈&#xff0c;是一种容器&#xff0c;可存入数据元素、访问元素、删除元素&#xff0c;它的特点在于只能允许在容器的一端&#xff08;称为栈顶端指标&#xff0c;英语&#xff1a;top&#xff09;进行加…