线程池监控2-监控线程池状态、线程数量和队列任务数量等

1.实现原理

  这篇博文是基于线程池监控1-监控任务执行时间,原理是:创建一个固定时间间隔执行的线程,来记录线程池的池状态、线程数量和队列任务数量等,具体方案:使用单例类缓存所有创建的线程池对象,类创建时启动定时任务线程,定期遍历缓存中线程池,记录线程池信息。

  使用单例类缓存所有创建的线程池对象,具体操作:在线程池创建的时候添加到缓存中,shutdown的时候从缓存中删除,只用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) throws InterruptedException {
        poolMonitor();
    }

    public static void poolMonitor() throws InterruptedException {
        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);
            });
        }
        //因为调用shutdown方法会将threadPoolMonitor从监控缓存中删除,这里sleep 100s
        TimeUnit.SECONDS.sleep(100);
        //线程池必须手动关闭,否则一直运行
        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
      https://gitee.com/xkzhangsan/thread-pool-monitor


posted @ 2024-10-10 12:19  xkzhangsanx  阅读(419)  评论(0编辑  收藏  举报