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数据库,今年人家说要换台服务器,要重新部署一下,好吧,虽然早就过了服务时间,但无奈谁叫人家是客户了,二话不说,上 ...
随机推荐
- Gos: Armed Golang 💪
Gos: Armed Golang
- HTML5中的Web Worker
什么是 Web Worker? 当在 HTML 页面中执行脚本时,页面是不可响应的,直到脚本已完成. Web worker 是运行在后台的 JavaScript,独立于其他脚本,不会影响页面的性能.您 ...
- Oracle 数字转为字符串 to_char()
格式:TO_CHAR(number,'format_model') 9 -->Represents a number 0 --> Forces a zero to be displayed ...
- git路径超长 及gitignore
1 忽略路径超长 git config --system core.longpaths true 2 比较全的gitignore https://www.gitignore.io/api/vim,no ...
- windowserver 常用命令
1.查看端口占用: netstat -ano | findstr "服务端口号"2.查看程序运行id: tasklist | findstr nginx 3.杀死进程 tskk ...
- json和dict 在requests中请求
上面的问题,在这么晚的夜里解决了 data 接受的是json格式数据, json 接受dict格式点的数据, 这个文章中也讲到了https://www.cnblogs.com/beile/p/1086 ...
- django之csrf_exempt解决跨域请求的问题
一: from django.views.decorators.csrf import csrf_exempt # 获取微信返回的code信息 @csrf_exempt def wechat_auth ...
- ht-7 treeSet特性
TreeSetTreeSet可以对set集合中的元素进行排序,默认按照asic码表的自然顺序排序,之所以treeset能排序是因为底层是二叉树,数据越多越慢,TreeSet是依靠TreeMap来实现的 ...
- ht-1 jdk calendar类
package calendardemo; import java.util.Calendar; public class CalendarDemo { /** * @param args */ pu ...
- Angular:ViewProviders和Providers的区别
在Angular中使用依赖注入(DI)的时候,我们一般会使用providers.其实要做同样的事我们还有另外一个选择:viewProviders. viewProviders允许我们定义只对组件的vi ...