1.实现原理
这篇博文是基于线程池监控1-监控任务执行时间,原理是:创建一个固定时间间隔执行的线程,来记录线程池的池状态、线程数量和队列任务数量等,具体方案:使用单例类缓存所有创建的线程池对象,类创建时启动定时任务线程,定期遍历缓存中线程池,记录线程池信息。
2.实现代码
package com.xkzhangsan.thread.pool.monitor;import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ScheduledThreadPoolExecutor; import java.util.concurrent.TimeUnit;/*** 全局监控 <br>* 1.定期记录线程池基本信息 <br>** @author xkzhangsan*/ public class GlobalMonitor {private static volatile GlobalMonitor instance;private static final ConcurrentHashMap<String, ThreadPoolMonitor> threadPoolMonitorMap = new ConcurrentHashMap<>();private static final ScheduledThreadPoolExecutor scheduledThreadPoolExecutor = new ScheduledThreadPoolExecutor(1);private GlobalMonitor() {scheduledThreadPoolExecutor.scheduleAtFixedRate(new PoolInfoRunnable(), 10, 10, TimeUnit.SECONDS);}public static GlobalMonitor getInstance() {if (instance == null) {synchronized (GlobalMonitor.class) {if (instance == null) {instance = new GlobalMonitor();}}}return instance;}public void put(String poolName, ThreadPoolMonitor threadPoolMonitor) {threadPoolMonitorMap.put(poolName, threadPoolMonitor);}public void remove(String poolName) {threadPoolMonitorMap.remove(poolName);}static class PoolInfoRunnable implements Runnable {@Overridepublic void run() {threadPoolMonitorMap.forEach((poolName, threadPoolMonitor) -> {int currentPoolSize = threadPoolMonitor.getPoolSize();int queueSize = threadPoolMonitor.getQueue().size();System.out.println("poolName:" + poolName + " status:" + threadPoolMonitor.getStatus() + " corePoolSize:" + threadPoolMonitor.getCorePoolSize() + " maximumPoolSize:"+ threadPoolMonitor.getMaximumPoolSize() + " currentPoolSize:" + currentPoolSize + " queueCapacity:" + threadPoolMonitor.getQueueCapacity()+ " queueSize:" + queueSize);});}}}
获取线程池状态
这里参考了ThreadPoolExecutor的toString(),返回Running、Shutting down、Terminated 三种状态。
见:ThreadPoolMonitor类
public String getStatus() {if (super.isTerminated()) {return "Terminated";} else if (super.isShutdown()) {return "Shutting down";} else {return "Running";}}
获取队列总容量
创建ThreadPoolExecutor时,传入的BlockingQueue<Runnable> workQueue,无法直接获取总容量,ThreadPoolExecutor又没有直接获取总容量的方法,
这里想到另一个方法,Queue的remainingCapacity()返回当前队列剩余容量,原理:总容量-队列size,所以,在刚创建时size为0,返回的就时总容量。
见:ThreadPoolMonitor类
private void init(String poolName, MonitorLevelEnum monitorLevel) {this.poolName = poolName;this.monitorLevel = monitorLevel;this.taskStartTimeMap = new ConcurrentHashMap<>();if (isPoolMonitor()) {GlobalMonitor.getInstance().put(poolName, this);}this.queueCapacity = super.getQueue().remainingCapacity();}public int getQueueCapacity() {return this.queueCapacity;}
3.测试运行
3.1 测试代码
package com.xkzhangsan.thread.pool.monitor;import com.xkzhangsan.thread.pool.monitor.constant.MonitorLevelEnum;import java.util.concurrent.ArrayBlockingQueue; import java.util.concurrent.TimeUnit;public class ThreadPoolMonitorTest {public static void main(String[] args) {poolMonitor();}public static void poolMonitor() {ThreadPoolMonitor threadPoolMonitor = new ThreadPoolMonitor(1, 3, 0, TimeUnit.MILLISECONDS, new ArrayBlockingQueue<>(1000), "test", MonitorLevelEnum.POOL);for (int i = 0; i < 100; i++) {int finalI = i;threadPoolMonitor.execute(() -> {try {TimeUnit.SECONDS.sleep(3);} catch (InterruptedException e) {throw new RuntimeException(e);}System.out.println(finalI);});}threadPoolMonitor.shutdown();} }
3.2 测试结果
0 1 2 poolName:test status:Shutting down corePoolSize:1 maximumPoolSize:3 currentPoolSize:1 queueCapacity:1000 queueSize:96 3 4 5 poolName:test status:Shutting down corePoolSize:1 maximumPoolSize:3 currentPoolSize:1 queueCapacity:1000 queueSize:93 6 7 8 poolName:test status:Shutting down corePoolSize:1 maximumPoolSize:3 currentPoolSize:1 queueCapacity:1000 queueSize:90 9
线程sleep 3s,监控日志10s打印一次,队列中的任务在不断减少。
源代码地址:https://github.com/xkzhangsan/thread-pool-monitor