最近公司在搞大促压测,需要根据压测情况来配置线程池的参数。来达到最佳的效果。
由于一个机器现在是多实例部署的情况,所以理想化的线程数=cpu数*2的情况已经不适用了,需要根据压测的实际情况来调整。
所以写了一个通过外置配置文件(使用了阿里的diamond,当然也可以使用springCloud的config server)来达到不重启应用的情况下,动态的调整线程池的参数。
先贴上我的配置文件:一个非常简单的json字符串
{
"coolPoolSize":"8",
"maxPoolSize":"16",
"maxWaitQueueSize":"1024",
"keepAliveTime":"5",
"rejectedHandler":"AbortPolicy"
}
对于动态修改线程池的问题
我这里只修改了 核心线程数,最大线程池数,任务队列长度,超时时间,拒绝策略这5个配置项。
然后对于修改线程池这块改动过一版。
原先是打算设置一个静态的线程池对象EXECTOR,然后当监听到配置文件发生变动,直接改变EXECTOR的指向
相关伪代码
//指针指向新的线程池
EXECUTOR = new ThreadPoolExecutor(
corePoolSize
,maxPoolSize
,keepAliveTime
,TimeUnit.MILLISECONDS
,BLOCK_QUEUE
,FACTORY
,rejectedHandler);
但是这里存在一个隐患的点。如果采用了这套方案,若此时流量太大,我们去改变线程池的配置的时候,会在内存中生成两个线程池,另一个线程池得把任务执行完毕之后才会停止。双倍机器的负荷,容易产生隐患。
ThreadPoolExecutor其实已经提供了相关set方法,可以实时修改线程池的参数
EXECUTOR.setCorePoolSize(corePoolSize);
EXECUTOR.setMaximumPoolSize(maxPoolSize);
EXECUTOR.setKeepAliveTime(keepAliveTime,TimeUnit.MILLISECONDS);
EXECUTOR.setRejectedExecutionHandler(rejectedHandler);
但是却没有调整任务队列长度的能力,但是任务队列的长度也是需要考虑到的一个点,如果上来就是无界队列,是会存在oom的隐患的。
于是我又写了一点方法,提供了调整任务队列长度的能力
从这个角度出发,我们可以先关闭之前的线程池,然后把之前的任务搬到新的线程池中来执行。
相关方法
//动态调整线程池参数
private static void dynamicAdjustThreadPool(String content) {
Map<String,String> config = null;
try {
config = (Map<String, String>) JSON.parse(content);
} catch (Exception e) {
log.error("parse to hashmap error content = {} ",content,e);
return;
}
//核心线程数
Integer corePoolSize = getCorePoolSizeFromConfig(config);
//最大线程数
Integer maxPoolSize = getMaxPoolSizeFromConfig(config);
//超时时间
Integer keepAliveTime = getKeepAliveTimeFromConfig(config);
//任务队列长度
Integer maxWaitQueueSize = getMaxWaitQueueSizeFromConfig(config);
//拒绝策略
RejectedExecutionHandler rejectedHandler = getRejectedHandlerFromConfig(config);
if (EXECUTOR==null){
EXECUTOR = new ThreadPoolExecutor(
corePoolSize,
maxPoolSize,
keepAliveTime,
TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<>(maxWaitQueueSize),
FACTORY,
rejectedHandler);
}else {
//队列容量发生变化的时候。需要重新new一个新的线程池,再把老的任务搬迁过去
if (CURRENT_CAPACITY!=null && !CURRENT_CAPACITY.equals(maxWaitQueueSize)){
adjustIfNewCapacity(corePoolSize, maxPoolSize, keepAliveTime, maxWaitQueueSize, rejectedHandler);
}else {
//当队列长度没变化时
adjustIfOldCapacity(corePoolSize,maxPoolSize,keepAliveTime,rejectedHandler);
}
}
//更新当前容量
CURRENT_CAPACITY = maxWaitQueueSize;
}
/**
* 当队列长度发生变化时
* EXECUTOR指向新的线程池,并且把老的线程池中的任务搬迁过来
*/
private static void adjustIfNewCapacity(Integer corePoolSize,
Integer maxPoolSize,
Integer keepAliveTime