本章为预览版本,展示部分核心内容。完整内容包含详细源码解析、实战代码和面试要点,加入知识星球即可解锁全部章节。
第三章:一个 ConcurrentHashMap 里藏着所有线程池的秘密
本章目标:理解 DtpRegistry 如何用一个 Map 统一管理所有线程池,掌握三条注册路径的源码细节,理解 BeanPostProcessor 在 Spring 生命周期中的精妙应用。
3.1 核心问题
上一章讲了配置刷新,DtpRegistry.refresh() 是从一个 Map 里按名字找到线程池再更新的。
那这个 Map 是怎么来的?线程池是什么时候被放进去的?
3.2 全局注册表:为什么是 ConcurrentHashMap + putIfAbsent
public class DtpRegistry {
// 全局注册表:线程池名称 → ExecutorWrapper
private static final Map<String, ExecutorWrapper> EXECUTOR_REGISTRY =
new ConcurrentHashMap<>();
public static void registerExecutor(ExecutorWrapper wrapper, String source) {
log.info("DynamicTp register executor: {}, source: {}",
ExecutorConverter.toMainFields(wrapper), source);
EXECUTOR_REGISTRY.putIfAbsent(wrapper.getThreadPoolName(), wrapper);
}
}
两个设计选择背后的思考:
为什么用 ConcurrentHashMap 而不是 HashMap + synchronized?
注册发生在 Spring 启动阶段(多个 BeanPostProcessor 可能并发执行),查找发生在运行时(监控采集、配置刷新)。读多写少的场景,ConcurrentHashMap 的分段锁机制天然适合,读操作几乎无锁。
为什么用 putIfAbsent 而不是 put?
防御式编程。如果同一个名字的线程池被注册两次(比如 YAML 配置和 @DynamicTp 注解同时定义了同名线程池),第二次会被静默忽略,不会破坏已有的线程池实例。
3.3 三条注册路径
路径1:YAML 配置自动创建
dynamictp:
executors:
- threadPoolName: orderExecutor
executorType: common
corePoolSize: 10
maximumPoolSize: 20
queueCapacity: 200
由 DtpBeanDefinitionRegistrar 在 Spring 启动阶段自动创建 DtpExecutor 实例。
路径2:@DynamicTp 注解标记
@DynamicTp("paymentExecutor")
@Bean
public ThreadPoolExecutor paymentExecutor() {
return new ThreadPoolExecutor(5, 10, 60L, TimeUnit.SECONDS,
new LinkedBlockingQueue<>(100));
}
用户自己创建的线程池,加注解就能被纳管。
路径3:第三方 Adapter 自动发现
Dubbo、RocketMQ 等中间件内置的线程池,由各 Adapter 模块在启动时自动发现并注册。不需要写任何代码。
3.4 源码深入:DtpBeanDefinitionRegistrar
DtpExecutor 的创建发生在 Spring 容器启动的 BeanDefinition 注册阶段:
@EnableDynamicTp
↓ @Import
DtpBeanDefinitionRegistrar.registerBeanDefinitions()
↓
读取 YAML: spring.dynamic.tp.executors
↓
遍历每个 autoCreate=true 的配置
↓
注册 BeanDefinition → Spring 实例化 DtpExecutor
核心源码:
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata,
BeanDefinitionRegistry registry) {
DtpProperties dtpProperties = DtpProperties.getInstance();
BinderHelper.bindDtpProperties(environment, dtpProperties);
val executors = dtpProperties.getExecutors();
if (CollectionUtils.isEmpty(executors)) {
return;
本章剩余内容需要解锁后查看
以上仅为本章部分预览内容,完整内容包含更多深度源码解析、实战代码和面试要点。
加入知识星球你将获得:
- ✅ 全部 12 章完整内容 + 持续更新
- ✅ 配套源码 + 实战项目
- ✅ 一对一答疑 + 面试辅导
- ✅ 简历优化 + 内推机会
📚 本章完整目录
以下为本章完整目录结构,加入知识星球即可解锁全部内容。