JAVA|项目体验(高并发httpclient和线程池的正确使用)
这段时间以来都在同事在研发一个公司的新项目,其中使用到了一个技术,由于不熟悉而导致了一些性能上的问题。现简略作一下总结。
1、ExecutorService
用这个java提供的线程池机制还是很方便的,比自己写的池好得多。一般都会使用 ExecutorService normalExService = Executors.newFixedThreadPool(30) 来指定一个有30个固定大小线程的池。这只是新建了个池子,只有往里面放入thread类对象时才会运行。方法是调用
exService.execute(msgThread)
execute()相当于把一个继承了Thread或实现了Runnable接口的线程类当成一个任务加入到pool中。一个task一旦被加入到了pool,则由空闲的thread去竞争获取并执行。
如果execute了10次,怎么判断这10个task都完成了呢。
while (!exService.isTerminated()) {
// 执行中
}
可以用一个while,用exService.isTerminated()来判断是否所有的task都完成。嗯。。这些都不是要说的问题。试想一下。如果一直不停地往pool中加入task,但是task的处理速度远跟不上加入的速度,但造成pool积压严重。其实如果只一个空的task,也不会有多大问题。用JProfiler看了一下JVM,发现40w个task,本身也只有10m左右。
但是,如果task中又包含了很多对象,如字符串,map,list等等,在生成task时也会把这些东西一起生成,即使加了pool中,又不会马上执行到,只能是空站着耗内存罢了。
【JAVA|项目体验(高并发httpclient和线程池的正确使用)】所以程序运行一段时间后,JVM越来越小,十几分钟后就达到了最大值,此时程序也越来越慢。最后打印出 heap outofmenery就挂了。另外说一点。一般控制台只是会说内存溢出,但是具体是什么东西占了空间是无法得知了,所以必须要有文件可以看。
在Tomcat的catalina第一行配置 set JAVA_OPTS=%JAVA_OPTS% -server -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=D:\heapdump
就会在程序因为内存溢出崩掉了输出一个记录了崩溃时JVM和程序的具体信息,很有帮助,就像飞机的黑匣子一样。
既然不能一次性把task全加入到pool中,那只能等到pool中有空闲线程时再join。这样pool只也许只会有30个(配的30)task。组内的王大师利用星期天的时间,边抱着孩子边写设计了一个算法,解决了上述问题。
不用execute了,用submit
List futures = new ArrayList();
ExecutorService pool = Executors. newFixedThreadPool(poolSize);
Future future = null;
List tempFutures = null;
while(true) {
//判断队列是否有数据
if(queue.size() > 0) {
if(futures.size() == poolSize) {//------------------------------1
tempFutures = new ArrayList();
for(int i = 0;
i < poolSize;
i++ ) {
future = futures.get(i);
if(! future.isDone()) {
tempFutures.add(future);
}
}
futures = tempFutures;
}
else { // ----------------------------------------2
BizBean biz = new BizBean();
biz.initBean((String) queue.poll());
future = pool.submit(biz);
//
futures.add(future);
}
}
}
submit():Submits a Runnable task for execution and returns a Future representing that task。Future代表了当前的task。在这里我定义了一个List
使用了这个后,task实例就一直维持在一个合理的数量,相关的类、对象也不会创建,不会再像使用execute时一股脑地全部join到pool中空占内存了。
htticlient请见下篇blog
??
??
推荐阅读
- JAVA(抽象类与接口的区别&重载与重写&内存泄漏)
- 事件代理
- Java|Java OpenCV图像处理之SIFT角点检测详解
- java中如何实现重建二叉树
- 绘本讲师训练营【18期】14/21《我的情绪小怪兽》故事会新体验
- 数组常用方法一
- 【Hadoop踩雷】Mac下安装Hadoop3以及Java版本问题
- 美之初体验—我所感受到的那一点儿
- Java|Java基础——数组
- 17|17 关山松 第二课作业#公众号项目# D20