跳到主要内容
📖 本章预览

本章为预览版本,展示部分核心内容。完整内容包含详细源码解析、实战代码和面试要点,加入知识星球即可解锁全部章节。

第三章:一个 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 章完整内容 + 持续更新
  • ✅ 配套源码 + 实战项目
  • ✅ 一对一答疑 + 面试辅导
  • ✅ 简历优化 + 内推机会

📚 本章完整目录

以下为本章完整目录结构,加入知识星球即可解锁全部内容。

3.5 源码深入:DtpPostProcessor

3.6 ExecutorWrapper:统一包装的核心抽象

3.7 EventBus 事件驱动:容器就绪后对齐配置

3.8 完整时序

3.9 本章涉及的设计模式