SpringBoot监控所有线程池的四种解决方案及代码案例
更新时间:2025年12月01日 10:00:03 作者:学亮编程手记
这篇文章介绍了四种监控Spring Boot中所有线程池的解决方案,并提供了代码案例,推荐使用自动发现机制来监控所有线程池,需要的朋友可以参考下
问题分析
1.默认监控的局限性
@Component
public class ThreadPoolMonitor {
@Autowired
private ThreadPoolTaskExecutor taskExecutor; // 只能监控这一个线程池
public void monitor() {
// 只能监控 taskExecutor 这个特定的bean
System.out.println("活跃线程: " + taskExecutor.getActiveCount());
}
}
解决方案
方案1:手动注册所有线程池
@Component
public class ThreadPoolMonitor {
private final Map<String, ThreadPoolTaskExecutor> executors = new ConcurrentHashMap<>();
// 手动注册线程池
public void registerExecutor(String name, ThreadPoolTaskExecutor executor) {
executors.put(name, executor);
}
@Scheduled(fixedRate = 30000)
public void monitorAll() {
executors.forEach((name, executor) -> {
ThreadPoolExecutor pool = executor.getThreadPoolExecutor();
log.info("线程池[{}] - 活跃: {}/{}, 队列: {}/{}, 完成: {}",
name,
pool.getActiveCount(),
pool.getPoolSize(),
pool.getQueue().size(),
pool.getQueue().remainingCapacity() + pool.getQueue().size(),
pool.getCompletedTaskCount());
});
}
}
// 在配置中注册
@Configuration
public class ExecutorConfig {
@Autowired
private ThreadPoolMonitor monitor;
@Bean("emailExecutor")
public ThreadPoolTaskExecutor emailExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
// 配置...
executor.initialize();
// 注册到监控器
monitor.registerExecutor("emailExecutor", executor);
return executor;
}
@Bean("smsExecutor")
public ThreadPoolTaskExecutor smsExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
// 配置...
executor.initialize();
monitor.registerExecutor("smsExecutor", executor);
return executor;
}
}
方案2:自动发现所有线程池(推荐)
@Component
public class GlobalThreadPoolMonitor {
@Autowired
private ApplicationContext applicationContext;
@Scheduled(fixedRate = 30000)
public void monitorAllThreadPools() {
// 获取所有 ThreadPoolTaskExecutor 类型的bean
Map<String, ThreadPoolTaskExecutor> executors =
applicationContext.getBeansOfType(ThreadPoolTaskExecutor.class);
// 获取所有 ThreadPoolExecutor 类型的bean(直接创建的)
Map<String, ThreadPoolExecutor> nativeExecutors =
applicationContext.getBeansOfType(ThreadPoolExecutor.class);
log.info("=== 线程池监控报告 ===");
// 监控 Spring 封装的线程池
executors.forEach((beanName, executor) -> {
if (executor.getThreadPoolExecutor() != null) {
printPoolStats(beanName, executor.getThreadPoolExecutor());
}
});
// 监控原生线程池
nativeExecutors.forEach((beanName, executor) -> {
printPoolStats(beanName, executor);
});
}
private void printPoolStats(String name, ThreadPoolExecutor executor) {
log.info("线程池[{}]: 活跃{}/核心{}, 队列{}/{}, 完成任务: {}, 拒绝: {}",
name,
executor.getActiveCount(),
executor.getPoolSize(),
executor.getQueue().size(),
executor.getQueue().size() + executor.getQueue().remainingCapacity(),
executor.getCompletedTaskCount(),
executor.getRejectedExecutionHandler().getClass().getSimpleName());
}
}
方案3:监控 @Async 使用的线程池
@Component
public class AsyncThreadPoolMonitor {
@Autowired
private ApplicationContext applicationContext;
@Scheduled(fixedRate = 30000)
public void monitorAsyncPools() {
try {
// 通过反射获取Spring内部的线程池
Map<String, Executor> asyncExecutors =
applicationContext.getBeansOfType(Executor.class);
asyncExecutors.forEach((name, executor) -> {
if (executor instanceof ThreadPoolTaskExecutor) {
ThreadPoolExecutor pool = ((ThreadPoolTaskExecutor) executor).getThreadPoolExecutor();
printAsyncPoolStats(name, pool);
} else if (executor instanceof ThreadPoolExecutor) {
printAsyncPoolStats(name, (ThreadPoolExecutor) executor);
} else if (executor instanceof TaskExecutor) {
log.info("Executor [{}]: 类型 {}", name, executor.getClass().getSimpleName());
}
});
} catch (Exception e) {
log.warn("监控异步线程池失败: {}", e.getMessage());
}
}
private void printAsyncPoolStats(String name, ThreadPoolExecutor pool) {
double usageRate = pool.getMaximumPoolSize() > 0 ?
(double) pool.getActiveCount() / pool.getMaximumPoolSize() * 100 : 0;
log.warn("异步线程池[{}]: 活跃{}/最大{}, 使用率: {:.1f}%, 队列: {}/{}",
name,
pool.getActiveCount(),
pool.getMaximumPoolSize(),
usageRate,
pool.getQueue().size(),
pool.getQueue().size() + pool.getQueue().remainingCapacity());
}
}
方案4:集成Micrometer监控(生产环境推荐)
@Component
public class MicrometerThreadPoolMonitor {
private final MeterRegistry meterRegistry;
private final List<ThreadPoolExecutor> monitoredPools = new ArrayList<>();
public MicrometerThreadPoolMonitor(MeterRegistry meterRegistry) {
this.meterRegistry = meterRegistry;
}
// 注册要监控的线程池
public void registerPool(String name, ThreadPoolExecutor pool) {
monitoredPools.add(pool);
// 注册指标
Gauge.builder("thread.pool.active.count", pool, ThreadPoolExecutor::getActiveCount)
.tag("pool", name)
.description("活跃线程数")
.register(meterRegistry);
Gauge.builder("thread.pool.queue.size", pool, p -> p.getQueue().size())
.tag("pool", name)
.description("队列大小")
.register(meterRegistry);
Gauge.builder("thread.pool.completed.tasks", pool, ThreadPoolExecutor::getCompletedTaskCount)
.tag("pool", name)
.description("完成任务数")
.register(meterRegistry);
}
@EventListener
public void onApplicationReady(ApplicationReadyEvent event) {
// 应用启动后自动发现并注册所有线程池
ApplicationContext context = event.getApplicationContext();
Map<String, ThreadPoolTaskExecutor> springExecutors =
context.getBeansOfType(ThreadPoolTaskExecutor.class);
Map<String, ThreadPoolExecutor> nativeExecutors =
context.getBeansOfType(ThreadPoolExecutor.class);
springExecutors.forEach((name, executor) -> {
if (executor.getThreadPoolExecutor() != null) {
registerPool("spring-" + name, executor.getThreadPoolExecutor());
}
});
nativeExecutors.forEach((name, executor) -> {
registerPool("native-" + name, executor);
});
log.info("已注册监控的线程池数量: {}", monitoredPools.size());
}
}
完整的生产级监控方案
@Configuration
public class ThreadPoolMonitorConfig {
@Bean
@ConditionalOnMissingBean
public GlobalThreadPoolMonitor globalThreadPoolMonitor() {
return new GlobalThreadPoolMonitor();
}
}
@Component
@Slf4j
public class GlobalThreadPoolMonitor {
@Autowired
private ApplicationContext applicationContext;
private final Map<String, ThreadPoolExecutor> allPools = new ConcurrentHashMap<>();
@PostConstruct
public void init() {
discoverAllThreadPools();
}
@Scheduled(fixedRate = 30000)
public void monitorAllPools() {
if (allPools.isEmpty()) {
discoverAllThreadPools();
}
log.info("======= 线程池监控报告 =======");
allPools.forEach(this::logPoolStatus);
log.info("======= 监控报告结束 =======");
}
private void discoverAllThreadPools() {
// 发现Spring封装的线程池
applicationContext.getBeansOfType(ThreadPoolTaskExecutor.class)
.forEach((name, executor) -> {
if (executor.getThreadPoolExecutor() != null) {
allPools.put("Spring-" + name, executor.getThreadPoolExecutor());
}
});
// 发现原生线程池
applicationContext.getBeansOfType(ThreadPoolExecutor.class)
.forEach((name, executor) -> {
allPools.put("Native-" + name, executor);
});
// 发现所有Executor(包括@Async使用的)
applicationContext.getBeansOfType(Executor.class)
.forEach((name, executor) -> {
if (executor instanceof ThreadPoolTaskExecutor) {
ThreadPoolExecutor pool = ((ThreadPoolTaskExecutor) executor).getThreadPoolExecutor();
allPools.putIfAbsent("Executor-" + name, pool);
} else if (executor instanceof ThreadPoolExecutor) {
allPools.putIfAbsent("Executor-" + name, (ThreadPoolExecutor) executor);
}
});
log.info("发现线程池数量: {}", allPools.size());
}
private void logPoolStatus(String name, ThreadPoolExecutor pool) {
int activeCount = pool.getActiveCount();
int poolSize = pool.getPoolSize();
int queueSize = pool.getQueue().size();
int queueCapacity = queueSize + pool.getQueue().remainingCapacity();
long completedTasks = pool.getCompletedTaskCount();
String status = (activeCount == 0) ? "空闲" : "忙碌";
double usageRate = pool.getMaximumPoolSize() > 0 ?
(double) activeCount / pool.getMaximumPoolSize() * 100 : 0;
if (usageRate > 80) {
log.warn("🚨 线程池[{}]: {} 活跃{}/最大{} (使用率{:.1f}%), 队列{}/{}",
name, status, activeCount, pool.getMaximumPoolSize(), usageRate,
queueSize, queueCapacity);
} else {
log.info("线程池[{}]: {} 活跃{}/核心{}, 队列{}/{}, 完成: {}",
name, status, activeCount, poolSize, queueSize, queueCapacity, completedTasks);
}
}
// 获取特定线程池状态
public ThreadPoolStats getPoolStats(String poolName) {
ThreadPoolExecutor pool = allPools.get(poolName);
if (pool != null) {
return new ThreadPoolStats(
pool.getActiveCount(),
pool.getPoolSize(),
pool.getQueue().size(),
pool.getQueue().remainingCapacity(),
pool.getCompletedTaskCount()
);
}
return null;
}
// 统计类
@Data
@AllArgsConstructor
public static class ThreadPoolStats {
private int activeCount;
private int poolSize;
private int queueSize;
private int queueRemainingCapacity;
private long completedTaskCount;
}
}
总结
- 默认情况下,
ThreadPoolMonitor只能监控直接注入的特定线程池 - 需要特殊处理才能监控所有线程池:
- 自动发现所有
ThreadPoolTaskExecutor和ThreadPoolExecutorbean - 注册机制手动管理
- 集成监控框架如 Micrometer
- 自动发现所有
- 生产推荐:使用方案2或方案4的自动发现机制
关键是要在应用启动后自动发现所有线程池实例,而不是依赖单个注入。
到此这篇关于SpringBoot监控所有线程池的四种解决方案及代码案例的文章就介绍到这了,更多相关SpringBoot监控所有线程池内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!
相关文章
深入研究spring boot集成kafka之spring-kafka底层原理
这篇文章主要深入研究了spring boot集成kafka如何实现spring-kafka的底层原理分析,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步2022-02-02
springboot解决使用localhost或127.0.01模拟CORS失效
CORS允许不同源的网页请求访问另一个源服务器上的某些资源,本文主要介绍了springboot解决使用localhost或127.0.01模拟CORS失效,文中通过示例代码介绍的非常详细,需要的朋友们下面随着小编来一起学习学习吧2024-07-07
MySQL中drop、truncate和delete的区别小结
在MySQL数据库管理中,常常需要执行删除数据的操作,本文主要介绍了MySQL中drop、truncate和delete的区别小结,具有一定的参考价值,感兴趣的可以了解一下2024-04-04
IDEA @SpringBootApplication报错原因及解决
这篇文章主要介绍了IDEA @SpringBootApplication报错原因及解决方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教2024-01-01
解决Nacos在执行startup.cmd的时候出现闪退的问题
因为在工作中的项目中需要使用到nacos作为注册中心,但是在使用nacos的过程中运行startup.cmd的时候出现了闪退的情况,运行startup.cmd闪一下就没有了,我把解决这个问题的全过程理了一下,希望能帮到您,需要的朋友可以参考下2023-12-12


最新评论