大部分情况下,线程池的运行情况对于使用者来说是个黑盒,运行情况不可知,会导致 生产出现事故问题排查困难,以及线程池参数难以定义。文章围绕线程池监控展开,讨论 线程池如何监控、监控的指标以及监控数据的存储展示
01、如何监控运行数据
设想一下,如果想监控线程池的运行数据,你会怎么操作?这里提供两种常规思路
1、线程池运行时埋点,每一次运行任务都进行统计
2、定时获取线程池的运行数据
这里我推荐第二种,因为线程池的监控 API 会通过 获取主锁来控制结果的相对准确性,性能相对较差,后面会详细说明。为什么叫相对准确?因为任务和线程的状态在计算过程中可能会动态变化,只能给到一个近似值,保证不了绝对准确,模拟下定时采集线程池运行时数据的代码。
private ScheduledThreadPoolExecutor collectVesselExecutor;
String collectVesselTaskName = "client.scheduled.collect.data";
collectVesselExecutor = new ScheduledThreadPoolExecutor(
new Integer(1),
ThreadFactoryBuilder.builder().daemon(true).prefix(collectVesselTaskName).build()
);
// 延迟 initialDelay 后循环调用. scheduleWithFixedDelay 每次执行时间为上一次任务结束时, 向后推一个时间间隔
collectVesselExecutor.scheduleWithFixedDelay(
() -> runTimeGatherTask(),
properties.getInitialDelay(),
properties.getCollectInterval(),
TimeUnit.MILLISECONDS
);
一般线程池分为两种方式创建,Spring Bean 和非 Spring Bean,假设创建的线程池是 Spring 管理的,我们只需要在 Spring 容器启动成功后,延迟一段时间后开始采集运行数据就 OK 了。
不论线程池是否由 Spring 管理,采集的方式大致相同。一种从 Spring 容器取,一种是创建好线程池后放到一个自定义容器。