线程池如何动态刷新?
1、 动态池注册
起初预定义N个默认的动态线程池【对应N种业务场景】。通过@Configuration + @Bean 的方式配置多个动态池默认实例Bean。
在 WebApplicationContext 初始化后通过实现org.springframework.beans.factory.config.BeanPostProcessor 接口的类将动态池的实例通过注册器注册。
public class RegistryDynamicTpProcessor implements BeanPostProcessor {
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
// 这里的 DynamicTpExecutor 是对动态池执行器的封装
if (bean instanceof DynamicTpExecutor) {
DynamicTpExecutor executor = (DynamicTpExecutor) bean;
// 注册动态池
registerDtp(executor);
return executor;
}
return bean;
}
}
这里的注册指的是将动态池实例使用 ConcurrentHashMap 缓存在本地。key为动态池唯一标识名称,value为实例。
业务代码使用时通过注册器提供的静态方法获取对应业务key的实例提交任务即可。
2、 通过配置中心更新动态池配置
实现分布式配置中心提供的属性监听器 PropertyListener。在对应配置更新时,PropertyListener#onUpdate() 方法接收到数据,刷新线程池配置[【这里会实时生效,即使当前某个线程池正在执行任务】。
@Slf4j
@Component
public class DynamicTpPropertyListener implements PropertyListener {
@Autowired
private Refresher refresher;
@Override
public void onUpdate(Property property) {
log.info("DynamicTpPropertyListener receive data, property: " + property);
refresher.refresh(property);
log.info("DynamicTpPropertyListener update dynamic thread pool success.");
}
}
3、 刷新机制
上文2中的监听器中使用到了刷新接口。这里的刷新接口 Refresh#refresh 本质上就是对 ThreadPoolExecutor 中一系列 setXXX() 方法的封装。