
最近想对线程池增加一下监控
先从https://grafana.com/grafana/dashboards/ 找到一个关于Spring Boot Executors的Grafana面板

竟然发现,已经有部分线程池被监控到了,记得以前都得使用ExecutorServiceMetrics包装一下,原来在Springboot 2.6.0版本提供了TaskExecutorMetricsAutoConfiguration,可以自动给线程池加上metrics
@AutoConfiguration(after = { MetricsAutoConfiguration.class, SimpleMetricsExportAutoConfiguration.class,
TaskExecutionAutoConfiguration.class, TaskSchedulingAutoConfiguration.class })
@ConditionalOnClass(ExecutorServiceMetrics.class)
@ConditionalOnBean({ Executor.class, MeterRegistry.class })
public class TaskExecutorMetricsAutoConfiguration {
@Autowired
public void bindTaskExecutorsToRegistry(Map<String, Executor> executors, MeterRegistry registry) {
executors.forEach((beanName, executor) -> {
if (executor instanceof ThreadPoolTaskExecutor) {
monitor(registry, safeGetThreadPoolExecutor((ThreadPoolTaskExecutor) executor), beanName);
}
else if (executor instanceof ThreadPoolTaskScheduler) {
monitor(registry, safeGetThreadPoolExecutor((ThreadPoolTaskScheduler) executor), beanName);
}
});
}
看源码,原理跟之前手动操作一样遍历executors,然后执行monitor方法,而monitor方法则是创建ExecutorServiceMetrics然后绑定到meterRegistry
ExecutorServiceMetrics 是 Micrometer 中专门用于监控 Java 线程池(ExecutorService)的工具。它可以帮助你实时了解线程池的运行状态,比如活跃线程数、队列积压、任务执行耗时等,这些指标对排查性能问题和优化线程池配置很有价值。
核心的使用方法有两种:直接包装(推荐) 和 构造器绑定。
指标名称会根据你的线程池类型(ThreadPoolExecutor 或 ForkJoinPool)略有不同:
指标名称 | 类型 | 描述 |
|---|---|---|
executor.active | Gauge | 当前正在执行任务的活跃线程数 |
executor.queued | Gauge | 队列中等待执行的任务数量 |
executor.completed | FunctionCounter | 线程池已完成的任务总数 |
executor.pool.size | Gauge | 线程池中当前的线程总数 |
executor | Timer | 记录任务执行的耗时分布(P99、P95等) |
executor.idle | Timer | 记录任务在队列中的等待耗时 |
executor.queue.remaining | Gauge | 队列剩余容量(ThreadPoolExecutor 特有) |
executor.steals | FunctionCounter | 工作窃取总数(ForkJoinPool 特有) |
确保你的项目中引入了 Micrometer 的核心依赖。
<dependency>
<groupId>io.micrometer</groupId>
<artifactId>micrometer-core</artifactId>
<version>最新版本</version>
</dependency>
monitor 方法)这是最常用的方式。monitor 方法会返回一个被 Micrometer 增强过的 ExecutorService 代理对象。你只需要像平常一样用它提交任务即可。
importio.micrometer.core.instrument.MeterRegistry;
importio.micrometer.core.instrument.binder.jvm.ExecutorServiceMetrics;
importjava.util.concurrent.ExecutorService;
importjava.util.concurrent.Executors;
publicclassExecutorMonitorDemo{
privateExecutorService monitoredExecutor;
publicExecutorMonitorDemo(MeterRegistry registry){
// 1. 创建原始的线程池
ExecutorService originalExecutor =Executors.newFixedThreadPool(10);
// 2. 用 Monitor 方法进行包装
// 参数说明:MeterRegistry, 原始Executor, 线程池名称(用于标签), 可选的额外标签
this.monitoredExecutor =ExecutorServiceMetrics
.monitor(registry, originalExecutor,"my-service-pool");
// 3. 使用被包装过的线程池执行任务
monitoredExecutor.submit(()->{
System.out.println("Task is being monitored!");
});
}
}
bindTo 方法)这种方式只注册指标,不返回代理对象。适用于你不想改变现有线程池引用的情况。
importio.micrometer.core.instrument.MeterRegistry;
importio.micrometer.core.instrument.binder.jvm.ExecutorServiceMetrics;
importio.micrometer.core.instrument.Tags;
importjava.util.concurrent.Executors;
importjava.util.concurrent.ThreadPoolExecutor;
// 假设你已有一个 threadPool 实例
ThreadPoolExecutor threadPool =(ThreadPoolExecutor)Executors.newFixedThreadPool(5);
// 创建 ExecutorServiceMetrics 实例,并绑定到 MeterRegistry
newExecutorServiceMetrics(threadPool,"my-pool-name",Tags.empty())
.bindTo(registry);