1 概述
在不停服务的基础上改变线程池的最大线程数,并使改变生效,关键点如下:
(1)通过线程池自带的方法设置线程池的最大线程数。
(2)通过配置中心触发线程池的最大线程数的改变。
2 具体实现
2.1 自定义线程池
@Slf4j
public class CommonThreadPoolUtil {
private static final int CORE_SIZE = Runtime.getRuntime().availableProcessors() * 2;
private static final int MAX_SIZE = CORE_SIZE + 10;
private static final int WORK_QUEUE_CAPACITY = 10000;
private static final long KEEP_ALIVE_TIME = 120;
private static final TimeUnit TIME_UNIT = TimeUnit.SECONDS;
/**
* 采用默认的队列策略,队列已满时拒绝任务
*/
private final static ThreadPoolExecutor EXECUTOR = new ThreadPoolExecutor(CORE_SIZE, MAX_SIZE, KEEP_ALIVE_TIME, TIME_UNIT,
new LinkedBlockingDeque<>(WORK_QUEUE_CAPACITY));
/**
* 功能描述:提交一个异步任务交给线程池执行
*/
public static void submitTask(String taskDesc, Runnable task) {
log.info("异步任务[{}]提交到线程池....", taskDesc);
try {
EXECUTOR.execute(task);
} catch (Exception e) {
log.error("异步任务[{}]提交到线程池失败", taskDesc, e);
}
}
/**
* 获取线程池
*/
public static ThreadPoolExecutor getExecutor() {
return EXECUTOR;
}
/**
* 设置线程池最大线程数
*/
public static void setMaximumPoolSize(Integer maximumPoolSize) {
if (maximumPoolSize < CORE_SIZE) {
log.info("CommonThreadPoolUtil.setMaximumPoolSize 设置失败. 最大线程数小于核心线程数。maximumPoolSize:{},CORE_SIZE:{}", maximumPoolSize, CORE_SIZE);
return;
}
int maximumPoolSizeOld = EXECUTOR.getMaximumPoolSize();
try {
EXECUTOR.setMaximumPoolSize(maximumPoolSize);
log.info("CommonThreadPoolUtil.setMaximumPoolSize 设置成功. 线程池最大线程数由{}变为{}", maximumPoolSizeOld, EXECUTOR.getMaximumPoolSize());
} catch (Exception e) {
log.error("CommonThreadPoolUtil.setMaximumPoolSize 设置失败. maximumPoolSize:{}", maximumPoolSize, e);
}
}
}
2.2 动态改变线程池的最大线程数
借助于apollo配置中心,对Apollo配置进行动态监听。
@Slf4j
@Component
public class ApolloListener implements CommandLineRunner {
@ApolloConfig("application.yml")
private Config config;
@Value("${commonThreadPoolUtil.maxPoolSize:0}")
private Integer maxPoolSize4CommonThreadPoolUtil;
@Override
public void run(String... args) throws Exception {
config.addChangeListener(changeEvent -> {
log.info("Apollo config changed for namespace:{} ", changeEvent.getNamespace());
changeEvent.changedKeys().forEach(key -> {
String oldValue = changeEvent.getChange(key).getOldValue();
String newValue = changeEvent.getChange(key).getNewValue();
log.info("Apollo config changed, key:{}, old value: {}, new value: {}", key, oldValue, newValue);
// 更新线程池最大线程数
setMaximumPoolSize( key, oldValue, newValue);
});
});
}
private void setMaximumPoolSize(String key, String oldValue, String newValue) {
if (Objects.equals(key, "commonThreadPoolUtil.maxPoolSize") && !Objects.equals(oldValue, newValue)) {
if (Integer.parseInt(newValue) < CommonThreadPoolUtil.getExecutor().getCorePoolSize()) {
log.warn("new value is less than core pool size, ignore");
return;
}
CommonThreadPoolUtil.setMaximumPoolSize(Integer.parseInt(newValue));
log.info("CommonThreadPoolUtil maximumPoolSize {}", CommonThreadPoolUtil.getExecutor().getMaximumPoolSize());
}
}
}
3 扩展
动态修改核心线程数和空闲线程存活时间的实现方式也可以采用类似方式实现。