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 {
@Override
public 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