執行緒池監控2-監控執行緒池狀態、執行緒數量和佇列任務數量等

xkzhangsanx發表於2024-10-10

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) 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


相關文章