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

尽然发现,已经有部分线程池被监控到了,记得以前都得使用ExecutorServiceMetrics包装一下,原来在Springboot 2.6.0版本提供了TaskExecutorMetricsAutoConfiguration,可以自动给线程池加上metrics
TaskExecutorMetricsAutoConfiguration
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| @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
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 特有) |
🛠️ 使用步骤
1. 添加依赖
确保你的项目中引入了 Micrometer 的核心依赖。
1 2 3 4 5
| <dependency> <groupId>io.micrometer</groupId> <artifactId>micrometer-core</artifactId> <version>最新版本</version> </dependency>
|
2. 方法一:直接包装(monitor 方法)
这是最常用的方式。monitor 方法会返回一个被 Micrometer 增强过的 ExecutorService 代理对象。你只需要像平常一样用它提交任务即可。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| import io.micrometer.core.instrument.MeterRegistry; import io.micrometer.core.instrument.binder.jvm.ExecutorServiceMetrics; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors;
public class ExecutorMonitorDemo {
private ExecutorService monitoredExecutor;
public ExecutorMonitorDemo(MeterRegistry registry) { ExecutorService originalExecutor = Executors.newFixedThreadPool(10); this.monitoredExecutor = ExecutorServiceMetrics .monitor(registry, originalExecutor, "my-service-pool"); monitoredExecutor.submit(() -> { System.out.println("Task is being monitored!"); }); } }
|
3. 方法二:构造器绑定(bindTo 方法)
这种方式只注册指标,不返回代理对象。适用于你不想改变现有线程池引用的情况。
1 2 3 4 5 6 7 8 9 10 11 12
| import io.micrometer.core.instrument.MeterRegistry; import io.micrometer.core.instrument.binder.jvm.ExecutorServiceMetrics; import io.micrometer.core.instrument.Tags; import java.util.concurrent.Executors; import java.util.concurrent.ThreadPoolExecutor;
ThreadPoolExecutor threadPool = (ThreadPoolExecutor) Executors.newFixedThreadPool(5);
new ExecutorServiceMetrics(threadPool, "my-pool-name", Tags.empty()) .bindTo(registry);
|