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数据库,今年人家说要换台服务器,要重新部署一下,好吧,虽然早就过了服务时间,但无奈谁叫人家是客户了,二话不说,上 ...
随机推荐
- spark复习笔记(4):spark脚本分析
1.[start-all.sh] #!/usr/bin/env bash # # Licensed to the Apache Software Foundation (ASF) under one ...
- 项目常见bug
Invalid prop: type check failed for prop "disabled". Expected Boolean, got String with val ...
- php WebService应用
<?php header ( "Content-Type: text/html; charset=gb2312" ); /* * 指定WebService路径并初始化一个We ...
- R语言封装函数
R语言封装函数 原帖见豆瓣:https://www.douban.com/note/279077707/ 一个完整的R函数,需要包括函数名称,函数声明,函数参数以及函数体几部分. 1. 函数名称,即要 ...
- 线上nginx 平滑添加新模块;如(--with-http_realip_module)
nginx 添加模块1.查看当前nginx信息(配置文件路径,启动用户...) ps aux | grep nginx 2.查看当前nginx已启用的模块(记录模块信息,安装路径)./nginx -V ...
- Linux忘记root密码解决方案
忘记Linux root密码时,只需重启Linux系统,然后引导进入Linux的单用户模式(init 1),由于单用户模式不需要输入登陆密码,因此,可直接登陆系统,修改root密码即可解决问题.需要说 ...
- 前端面试题:不使用loop循环,创建一个长度为100的数组,并且每个元素的值等于它的下标,,怎么实现好?
昨天,看这道题,脑子锈住了,就是没有思路,没看明白是什么意思?⊙﹏⊙|∣今天早上起床,想到需要思考一下这个问题. 当然,我没想明白为什么要这样做?(创建一个长度为100的数组,并且每个元素的值等于它的 ...
- tensorflow函数介绍(4)
1.队列的实现: import tensorflow as tf q=tf.FIFOQueue(2,'int32') #创建一个先进先出队列,指定队列中最多可以保存两个元素,并指定类型为整数. #先进 ...
- vscode中执行gulp task的简便方法
本文重点是gulp在vscode中执行task任务的方法 如何像webstorm那样简便操作gulp 的task 第1步:安装node.下载地址:https://nodejs.org/zh-cn/ 检 ...
- php中间件是什么
php中间件(middleware)是一个闭包,而且返回一个闭包. 中间件为过滤进入应用的HTTP请求提供了一套便利的机制,可以分为前置中间件和后置中间件.常用于验证用户是否经过认证,添加响应头(跨域 ...