CompletionService用法踩坑解决优化
转自:https://blog.csdn.net/xiao__miao/article/details/86352380
1.近期工作的时候,运维通知一个系统的内存一直在增长,leader叫我去排查,我开始看了一下,没处理,leader自己去看了一下,发现是线程池的问题,我开头没注意那块,一看才发现,确实因为CompletionService里的结果队列引起的。CompletionService里面有一个BlockingQueue维护结果,如果不去取结果就会导致一直里面一直增长
@SuppressWarnings("unchecked")
public void doExecute(Msg msg, List<Object> actList) {
try {
// 1、开启任务处理mq消息
service.submit(new ActMqTask(msg, actList));
} catch (Exception e) {
LOG.error(prefix + " doExecute is Exception", e);
msg.setStatus(MqMsgStatus.PROCESS);
msg.setResultDesc("消息处理异常" + e.getMessage());
} }
就这段代码,里面没有去消费这个结果队列,导致结果队列一直增长。
已经找原因了,那现在分析下这个ExecutorCompletionService
分析前,我是会默认当前读者是会使用线程池以及了解FutureTask了,不熟悉的源码强烈建议看下这篇博文Java线程池源码分析,读完可能理解就轻松许多
接下来我们就进入分析阶段
1.ExecutorCompletionService
来看下这段代码,网上都有的
public static void main(String[] args) throws InterruptedException, ExecutionException { Random random = new Random();
ExecutorService pool = Executors.newFixedThreadPool(3); CompletionService<String> service = new ExecutorCompletionService<String>(pool); for(int i = 0; i<4; i++) { service.submit(() -> {
Thread.sleep(random.nextInt(1000));
System.out.println(Thread.currentThread().getName()+"|完成任务");
return "data"+random.nextInt(10);
});
} for(int j = 0; j < 4; j++) {
Future<String> take = service.take(); //这一行没有完成的任务就阻塞
String result = take.get(); // 这一行在这里不会阻塞,引入放入队列中的都是已经完成的任务
System.out.println("获取到结果:"+result);
}
} CompletionService里的结果集,就是take出来的结果,不是先进先出原则,先完成先出 所以你放入blockingQueue<Future<V>>都是已经完成的执行结果。所以take去拿的时候都是由结果的不会去阻塞 public class ExecutorCompletionService<V> implements CompletionService<V> {
private final Executor executor;
private final AbstractExecutorService aes;
private final BlockingQueue<Future<V>> completionQueue; 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;
}
public Future<V> submit(Callable<V> task) {
if (task == null) throw new NullPointerException();
RunnableFuture<V> f = newTaskFor(task);
executor.execute(new QueueingFuture(f));
return f;
}
.......
} 这里主要重写了FutureTask<Void>里的done方法,执行完之后把结果集放入blockQueue里
再贴一段日常的结果集代码,与之对比
public static void main(String[] args) throws InterruptedException, ExecutionException { Random random = new Random();
ExecutorService pool = Executors.newFixedThreadPool(5);
List<Future<String>> resultFuture = new ArrayList<>(); for(int i = 0; i<4; i++) {
final int tmp = i;
Future<String> future = pool.submit(() -> {
Thread.sleep(1000+10*tmp);
System.out.println(Thread.currentThread().getName()+"|完成任务");
return "data"+random.nextInt(10);
});
resultFuture.add(future);
}
System.out.println("--------------"); for(Future<String> future:resultFuture) {
String result = future.get();
System.out.println("执行结果"+result);
}
}
区别对比
1.上面这段代码里没有维护一个结果集的队列
2.取出的结果的不同和执行效率的不同。ExecutorCompletionService里拿结果是最快的,他是根据里面的任务完成就取出。而上面那段代码是根据任务先后顺序然后取出结果集。
注意:
一:结果集的顺序,因为ExecutorCompletionService是根据完成的先后,顺序是不定的
CompletionService用法踩坑解决优化的更多相关文章
- RabbitMQ延迟消息:死信队列 | 延迟插件 | 二合一用法+踩坑手记+最佳使用心得
前言 前段时间写过一篇: # RabbitMQ:消息丢失 | 消息重复 | 消息积压的原因+解决方案+网上学不到的使用心得 很多人加了我好友,说很喜欢这篇文章,也问了我一些问题. 因为最近工作比较忙, ...
- IDEA打包javaFX及踩坑解决
开门见山的说,先打包,再说坑. File-->Project Structure --> Artifacts-->(此处点加号)JAR-->From modules with ...
- EasyPoi 导入导出Excel时使用GroupName的踩坑解决过程
一.开发功能介绍: 简单的一个excel导入功能 二.Excel导入模板(大致模板没写全): 姓名 性别 生日 客户分类 联系人姓名 联系人部门 备注 材料 综合 采购 张三 男 1994/05/25 ...
- [Python3]踩坑实录-优化技巧1
选择合适的数据结构 考虑不同的应用场景,应选择不同的数据结构 比如在查找多于插入的场景中,考虑字典Dict是不是更适合; 因为在Python3中, 字典Dict 通过hash把key映射到hash t ...
- ubuntu18.04 搭建scrapy环境(连环踩坑+解决办法)
---恢复内容开始--- 预期需求: 打算搭建scrapy环境,基于python3.x的 环境描述: ubuntu18.04自带了python3.6,打算在虚拟环境vlenv中跑scrapy,装好虚拟 ...
- 编译课设·CLion到VS踩坑·解决·备忘录
应试用,VS使用习惯和JB系差别还是蛮大的 打不过他们就加入他们 键位修改 工具-选项 键盘:改keymap 字体和颜色:宋体必改. 自动恢复:自动保存默认3分钟 CMake:自救时可以看一下 键位名 ...
- Idea运行支付宝网站支付demo踩坑解决及其测试注意事项
一.前言 在一些商城网上中,必不可少的是支付,支付宝和微信比较常见,最近小编也是在研究这一块,看看支付宝怎么进行支付的,支付宝给我们提供了demo和沙箱测试.减少我们的申请的麻烦,公钥和秘钥也比之前方 ...
- 用户数从 0 到亿,我的 K8s 踩坑血泪史
作者 | 平名 阿里服务端开发技术专家 导读:容器服务 Kubernetes 是目前炙手可热的云原生基础设施,作者过去一年上线了一个用户数极速增长的应用:该应用一个月内日活用户从零至四千万,用户数从零 ...
- 【踩坑经历】一次Asp.NET小网站部署踩坑和解决经历
2013年给1个大学的小客户部署过一个小型的Asp.NET网站,非常小,用的sqlite数据库,今年人家说要换台服务器,要重新部署一下,好吧,虽然早就过了服务时间,但无奈谁叫人家是客户了,二话不说,上 ...
随机推荐
- 你真的了解iOS的深浅拷贝吗?
最近在简书看到了一篇关于iOS深浅拷贝的博客,下面做一下学习总结: 非集合类对象的copy和mutableCopy 非集合类对象指NSString.NSNumber.NSMutableString等对 ...
- React-请求篇
请求方式: (1)后台API:HttpPost [FromForm] UserRetisterDTO dto 前端请求: { body:qs.stringify(dto), header ...
- 2018-2-13-win10-uwp-smms图床
title author date CreateTime categories win10 uwp smms图床 lindexi 2018-2-13 17:23:3 +0800 2018-2-13 1 ...
- 使用Python和AWK两种方式实现文本处理的长拼接案例
最近由于业务系统新需求的需要,我们平台需要将供应商G提供一类数据转换格式后提供给客户K.比较头疼是供应商G提供的数据都是在Windows下使用Excel存储的,而客户K先前与我们相关对接人员商定的数据 ...
- Oracle11gR2 64bit+Oracle11gR2Client32bit+pl/sql 9
安装Oracle数据库,费了老一番折腾准备软件:1. Oracle 11g R2 64bit2. Oracle 11g R2 Client 32bit3. PLSQL Developer V9 逐个安 ...
- 23飞机大战__pygame 快速入门
1. 使用 pygame 创建图形窗口 小节目标 游戏的初始化和退出 理解游戏中的坐标系 创建游戏主窗口 简单的游戏循环 可以将图片素材 绘制 到 游戏的窗口 上, 开发游戏之前需要先知道 如何建 ...
- file 显示文件的类型
1. 命令功能 file命令是确定文件类型,也可以辨识一些文件的编码格式.通过文件的头部信息来获取文件类型.windows是通过扩展名来确定文件类型. 2. 语法格式 file [option] ...
- java selenium常用API汇总
(WebElement.iFrame.select.alert.浏览器窗口.事件.js) 一 WebElement相关方法 1.点击操作 WebElement button = driver. ...
- thinkphp 数据库连接报错 SQLSTATE[HY000] [2002] No such file or directory
https://blog.csdn.net/tornge/article/details/51388233 找到mysql sokcet的路径 vim /etc/mysql/mysql.conf.d/ ...
- 解决Debug JDK source 无法查看局部变量的问题方案
一.问题阐述首先我们要明白JDK source为什么在debug的时候无法观察局部变量,因为在jdk中,sun对rt.jar中的类编译时,去除了调试信息,这样在eclipse中就不能看到局部变量的值. ...