教你如何監控 Java 線程池運行狀態的操作(必看)

之前寫過一篇 Java 線程池的使用介紹文章《線程池全面解析》,全面介紹瞭什麼是線程池、線程池核心類、線程池工作流程、線程池分類、拒絕策略、及如何提交與關閉線程池等。

但在實際開發過程中,在線程池使用過程中可能會遇到各方面的故障,如線程池阻塞,無法提交新任務等。

如果你想監控某一個線程池的執行狀態,線程池執行類 ThreadPoolExecutor 也給出瞭相關的 API, 能實時獲取線程池的當前活動線程數、正在排隊中的線程數、已經執行完成的線程數、總線程數等。

總線程數 = 排隊線程數 + 活動線程數 + 執行完成的線程數

下面給出一個線程池使用示例,及教你獲取線程池狀態

private static ExecutorService es = new ThreadPoolExecutor(50, 100, 0L, TimeUnit.MILLISECONDS,
 new LinkedBlockingQueue<Runnable>(100000));
public static void main(String[] args) throws Exception {
 for (int i = 0; i < 100000; i++) {
 es.execute(() -> {
 System.out.print(1);
 try {
 Thread.sleep(1000);
 } catch (InterruptedException e) {
 e.printStackTrace();
 }
 });
 }

 ThreadPoolExecutor tpe = ((ThreadPoolExecutor) es);
 while (true) {
 System.out.println();
 int queueSize = tpe.getQueue().size();
 System.out.println("當前排隊線程數:" + queueSize);
 int activeCount = tpe.getActiveCount();
 System.out.println("當前活動線程數:" + activeCount);
 long completedTaskCount = tpe.getCompletedTaskCount();
 System.out.println("執行完成線程數:" + completedTaskCount);
 long taskCount = tpe.getTaskCount();
 System.out.println("總線程數:" + taskCount);
 Thread.sleep(3000);
 }
}

線程池提交瞭 100000 個任務,但同時隻有 50 個線程在執行工作,我們每陋 3 秒來獲取當前線程池的運行狀態。

第一次程序輸出:

當前排隊線程數:99950

當前活動線程數:50

執行完成線程數:0

總線程數(排隊線程數 + 活動線程數 + 執行完成線程數):100000

第二次程序輸出:

當前排隊線程數:99800

當前活動線程數:50

執行完成線程數:150

總線程數(排隊線程數 + 活動線程數 + 執行完成線程數):100000

活動線程數和總線程數是不變的,排隊中的線程數和執行完成的線程數不斷在變化,

直到所有任務執行完畢,最後輸出:

當前排隊線程數:0

當前活動線程數:0

執行完成線程數:100000

總線程數(排隊線程數 + 活動線程數 + 執行完成線程數):100000

這樣,你瞭解瞭這些 API 的使用方法,你想監控線程池的狀態就非常方便瞭。

補充:Java線程及Jvm監控工具

Java線程狀態

線程的五種狀態

* 新建:new(時間很短)

* 運行:runnable

* 等待:waitting(無限期等待),timed waitting(限期等待)

* 阻塞:blocked

* 結束:terminated(時間很短)

Jvm監控工具

一、jstack

介紹:

jstack用於打印出給定的java進程ID或core file或遠程調試服務的Java堆棧信息。

如果是在64位機器上,需要指定選項”-J-d64″,Windows的jstack使用方式隻支持以下的這種方式:jstack [-l] pid

如果java程序崩潰生成core文件,jstack工具可以用來獲得core文件的java stack和native stack的信息,從而可以輕松地知道java程序是如何崩潰和在程序何處發生問題。

另外,jstack工具還可以附屬到正在運行的java程序中,看到當時運行的java程序的java stack和native stack的信息, 如果現在運行的java程序呈現hung的狀態,jstack是非常有用的。

使用:

1、查看運行程序的進程號

2、jstack dump當前線程狀態

3、根據當前抓取到的信息進行進一步的分析

二、jvisualvm

jdk自帶有個jvisualvm工具、該工具是用來監控java運行程序的cpu、內存、線程等的使用情況。並且使用圖表的方式監控java程序、還具有遠程監控能力。

前期準備

1、上傳tomcat到虛擬機,webapps下存在Prefteach包

2、監控之前先對jvm加監控參數,在tomcat的bin目錄下,catalina.sh文件中,搜索JAVA_OPTS=,在if裡面,添加:

-Dcom.sun.management.jmxremote.port=10086 -Dcom.sun.management.jmxremote.ssl=false -Dcom.sun.management.jmxremote.authenticate=false -Djava.rmi.server.hostname=192.168.1.101

以上添加的內容,需要修改兩處

1-改port

2-改hostname為本機ip

3、啟動tomcat並打開輸出日志:./startup.sh ../logs/catalina.out

jvisualvm使用

1、windows鍵+R鍵 輸入jvisualvm回車

2、右鍵遠程添加遠程主機

3、在 主機ip 上右鍵添加jmv連接

4、輸入遠程連接的端口號點擊確定

5、雙擊192.168.1.101:10086,打開如下圖所示的界面

6、進入jvisualvm時時查看程序運行狀態

註釋:在測試環境中有可能沒有權限在服務器上添加需要遠程連接的配置,這樣隻能使用jstack

補充:java 如何獲得線程池中正在執行的線程數

java中線程池的監控可以檢測到正在執行的線程數。

通過線程池提供的參數進行監控。線程池裡有一些屬性在監控線程池的時候可以使用

taskCount:線程池需要執行的任務數量。

completedTaskCount:線程池在運行過程中已完成的任務數量。小於或等於taskCount。

largestPoolSize:線程池曾經創建過的最大線程數量。通過這個數據可以知道線程池是否滿過。如等於線程池的最大大小,則表示線程池曾經滿瞭。

getPoolSize:線程池的線程數量。如果線程池不銷毀的話,池裡的線程不會自動銷毀,所以這個大小隻增不+ getActiveCount:獲取活動的線程數。

通過擴展線程池進行監控。通過繼承線程池並重寫線程池的beforeExecute,afterExecute和terminated方法,我們可以在任務執行前,執行後和線程池關閉前幹一些事情。

如監控任務的平均執行時間,最大執行時間和最小執行時間等。這幾個方法在線程池裡是空方法。

如:

protected void beforeExecute(Thread t, Runnable r) { }

以上為個人經驗,希望能給大傢一個參考,也希望大傢多多支持WalkonNet。如有錯誤或未考慮完全的地方,望不吝賜教。

推薦閱讀: