📖 本章预览
本章为预览版本,展示部分核心内容。完整内容包含详细源码解析、实战代码和面试要点,加入知识星球即可解锁全部章节。
第九章:线程池跑满了你还在看日志 — 监控告警体系
9.1 问题场景
JDK 的 ThreadPoolExecutor 虽然暴露了 getActiveCount()、getQueueSize() 等方法,但没有主动采集和推送机制。你不知道线程池什么时候快满了、任务排队多久了、有没有超时。等到出问题时,往往已经来不及了。
DynamicTP 构建了一套完整的监控体系:定时调度采集 → 指标转换 → 多通道输出,覆盖 25+ 监控指标,支持 Micrometer / Log / JMX / SPI 自定义四种采集通道。
9.2 DtpMonitor — 定时调度引擎
@Slf4j
public class DtpMonitor {
private static ScheduledExecutorService monitorExecutor;
private final DtpProperties dtpProperties;
private ScheduledFuture<?> monitorFuture;
private int monitorInterval;
/**
* 容器刷新时启动定时任务
*/
@Subscribe
public synchronized void onContextRefreshedEvent(
CustomContextRefreshedEvent event) {
// 间隔没变,不重建
if (monitorInterval == dtpProperties.getMonitorInterval()) {
return;
}
// 取消旧的定时任务
if (monitorFuture != null) {
monitorFuture.cancel(true);
}
if (monitorExecutor == null || monitorExecutor.isShutdown()) {
monitorExecutor = ThreadPoolCreator
.newScheduledThreadPool("dtp-monitor", 1);
}
monitorInterval = dtpProperties.getMonitorInterval();
// 按配置间隔定时执行
monitorFuture = monitorExecutor.scheduleWithFixedDelay(
this::run, 0, monitorInterval, TimeUnit.SECONDS);
}
private void run() {
Set<String> executorNames = DtpRegistry.getAllExecutorNames();
try {
checkAlarm(executorNames); // 先做告警检查
collectMetrics(executorNames); // 再做指标采集
} catch (Exception e) {
log.error("DynamicTp monitor, run error", e);
}
}
}
设计要点:
synchronized保证并发安全(配置热更新时可能触发多次)scheduleWithFixedDelay而非scheduleAtFixedRate:上一次执行完才开始计算下一次间隔,避免任务堆积- 支持热更新
monitorInterval:配置变更后自动取消旧任务、创建新任务 - 异常被 catch 不会中断定时调度
9.3 25+ 监控指标全景
指标来源分三层:
基础指标 — 从 ExecutorAdapter 直接读取
private static ThreadPoolStats convertCommon(ExecutorAdapter<?> executor) {
ThreadPoolStats poolStats = new ThreadPoolStats();
// 线程指标(5个)
poolStats.setCorePoolSize(executor.getCorePoolSize());
poolStats.setMaximumPoolSize(executor.getMaximumPoolSize());
poolStats.setPoolSize(executor.getPoolSize());
poolStats.setLargestPoolSize(executor.getLargestPoolSize());
poolStats.setActiveCount(executor.getActiveCount());
// 队列指标(3个)
poolStats.setQueueCapacity(executor.getQueueCapacity());
poolStats.setQueueSize(executor.getQueueSize());
poolStats.setQueueRemainingCapacity(executor.getQueueRemainingCapacity());
// 任务指标(3个)
poolStats.setTaskCount(executor.getTaskCount());
poolStats.setCompletedTaskCount(executor.getCompletedTaskCount());
poolStats.setWaitTaskCount(executor.getQueueSize());
return poolStats;
}
超时/拒绝计数 — 从 ThreadPoolStatProvider 的 LongAdder 读取
poolStats.setRunTimeoutCount(provider.getRunTimeoutCount());
poolStats.setQueueTimeoutCount(provider.getQueueTimeoutCount());
poolStats.setRejectCount(provider.getRejectedTaskCount());
🔒 解锁完整内容
本章剩余内容需要解锁后查看
以上仅为本章部分预览内容,完整内容包含更多深度源码解析、实战代码和面试要点。
加入知识星球你将获得:
- ✅ 全部 12 章完整内容 + 持续更新
- ✅ 配套源码 + 实战项目
- ✅ 一对一答疑 + 面试辅导
- ✅ 简历优化 + 内推机会
📚 本章完整目录
以下为本章完整目录结构,加入知识星球即可解锁全部内容。