教你如何監(jiān)控 Java 線程池運(yùn)行狀態(tài)的操作(必看)
之前寫過一篇 Java 線程池的使用介紹文章《線程池全面解析》,全面介紹了什么是線程池、線程池核心類、線程池工作流程、線程池分類、拒絕策略、及如何提交與關(guān)閉線程池等。
但在實(shí)際開發(fā)過程中,在線程池使用過程中可能會遇到各方面的故障,如線程池阻塞,無法提交新任務(wù)等。
如果你想監(jiān)控某一個線程池的執(zhí)行狀態(tài),線程池執(zhí)行類 ThreadPoolExecutor 也給出了相關(guān)的 API, 能實(shí)時(shí)獲取線程池的當(dāng)前活動線程數(shù)、正在排隊(duì)中的線程數(shù)、已經(jīng)執(zhí)行完成的線程數(shù)、總線程數(shù)等。
總線程數(shù) = 排隊(duì)線程數(shù) + 活動線程數(shù) + 執(zhí)行完成的線程數(shù)
下面給出一個線程池使用示例,及教你獲取線程池狀態(tài)
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("當(dāng)前排隊(duì)線程數(shù):" + queueSize); int activeCount = tpe.getActiveCount(); System.out.println("當(dāng)前活動線程數(shù):" + activeCount); long completedTaskCount = tpe.getCompletedTaskCount(); System.out.println("執(zhí)行完成線程數(shù):" + completedTaskCount); long taskCount = tpe.getTaskCount(); System.out.println("總線程數(shù):" + taskCount); Thread.sleep(3000); } }
線程池提交了 100000 個任務(wù),但同時(shí)只有 50 個線程在執(zhí)行工作,我們每陋 3 秒來獲取當(dāng)前線程池的運(yùn)行狀態(tài)。
第一次程序輸出:
當(dāng)前排隊(duì)線程數(shù):99950
當(dāng)前活動線程數(shù):50
執(zhí)行完成線程數(shù):0
總線程數(shù)(排隊(duì)線程數(shù) + 活動線程數(shù) + 執(zhí)行完成線程數(shù)):100000
第二次程序輸出:
當(dāng)前排隊(duì)線程數(shù):99800
當(dāng)前活動線程數(shù):50
執(zhí)行完成線程數(shù):150
總線程數(shù)(排隊(duì)線程數(shù) + 活動線程數(shù) + 執(zhí)行完成線程數(shù)):100000
活動線程數(shù)和總線程數(shù)是不變的,排隊(duì)中的線程數(shù)和執(zhí)行完成的線程數(shù)不斷在變化,
直到所有任務(wù)執(zhí)行完畢,最后輸出:
當(dāng)前排隊(duì)線程數(shù):0
當(dāng)前活動線程數(shù):0
執(zhí)行完成線程數(shù):100000
總線程數(shù)(排隊(duì)線程數(shù) + 活動線程數(shù) + 執(zhí)行完成線程數(shù)):100000
這樣,你了解了這些 API 的使用方法,你想監(jiān)控線程池的狀態(tài)就非常方便了。
補(bǔ)充:Java線程及Jvm監(jiān)控工具
Java線程狀態(tài)
線程的五種狀態(tài)
* 新建:new(時(shí)間很短)
* 運(yùn)行:runnable
* 等待:waitting(無限期等待),timed waitting(限期等待)
* 阻塞:blocked
* 結(jié)束:terminated(時(shí)間很短)
Jvm監(jiān)控工具
一、jstack
介紹:
jstack用于打印出給定的java進(jìn)程ID或core file或遠(yuǎn)程調(diào)試服務(wù)的Java堆棧信息。
如果是在64位機(jī)器上,需要指定選項(xiàng)"-J-d64",Windows的jstack使用方式只支持以下的這種方式:jstack [-l] pid
如果java程序崩潰生成core文件,jstack工具可以用來獲得core文件的java stack和native stack的信息,從而可以輕松地知道java程序是如何崩潰和在程序何處發(fā)生問題。
另外,jstack工具還可以附屬到正在運(yùn)行的java程序中,看到當(dāng)時(shí)運(yùn)行的java程序的java stack和native stack的信息, 如果現(xiàn)在運(yùn)行的java程序呈現(xiàn)hung的狀態(tài),jstack是非常有用的。
使用:
1、查看運(yùn)行程序的進(jìn)程號
2、jstack dump當(dāng)前線程狀態(tài)
3、根據(jù)當(dāng)前抓取到的信息進(jìn)行進(jìn)一步的分析
二、jvisualvm
jdk自帶有個jvisualvm工具、該工具是用來監(jiān)控java運(yùn)行程序的cpu、內(nèi)存、線程等的使用情況。并且使用圖表的方式監(jiān)控java程序、還具有遠(yuǎn)程監(jiān)控能力。
前期準(zhǔn)備
1、上傳tomcat到虛擬機(jī),webapps下存在Prefteach包
2、監(jiān)控之前先對jvm加監(jiān)控參數(shù),在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
以上添加的內(nèi)容,需要修改兩處
1-改port
2-改hostname為本機(jī)ip
3、啟動tomcat并打開輸出日志:./startup.sh ../logs/catalina.out
jvisualvm使用
1、windows鍵+R鍵 輸入jvisualvm回車
2、右鍵遠(yuǎn)程添加遠(yuǎn)程主機(jī)
3、在 主機(jī)ip 上右鍵添加jmv連接
4、輸入遠(yuǎn)程連接的端口號點(diǎn)擊確定
5、雙擊192.168.1.101:10086,打開如下圖所示的界面
6、進(jìn)入jvisualvm時(shí)時(shí)查看程序運(yùn)行狀態(tài)
注釋:在測試環(huán)境中有可能沒有權(quán)限在服務(wù)器上添加需要遠(yuǎn)程連接的配置,這樣只能使用jstack
補(bǔ)充:java 如何獲得線程池中正在執(zhí)行的線程數(shù)
java中線程池的監(jiān)控可以檢測到正在執(zhí)行的線程數(shù)。
通過線程池提供的參數(shù)進(jìn)行監(jiān)控。線程池里有一些屬性在監(jiān)控線程池的時(shí)候可以使用
taskCount:線程池需要執(zhí)行的任務(wù)數(shù)量。
completedTaskCount:線程池在運(yùn)行過程中已完成的任務(wù)數(shù)量。小于或等于taskCount。
largestPoolSize:線程池曾經(jīng)創(chuàng)建過的最大線程數(shù)量。通過這個數(shù)據(jù)可以知道線程池是否滿過。如等于線程池的最大大小,則表示線程池曾經(jīng)滿了。
getPoolSize:線程池的線程數(shù)量。如果線程池不銷毀的話,池里的線程不會自動銷毀,所以這個大小只增不+ getActiveCount:獲取活動的線程數(shù)。
通過擴(kuò)展線程池進(jìn)行監(jiān)控。通過繼承線程池并重寫線程池的beforeExecute,afterExecute和terminated方法,我們可以在任務(wù)執(zhí)行前,執(zhí)行后和線程池關(guān)閉前干一些事情。
如監(jiān)控任務(wù)的平均執(zhí)行時(shí)間,最大執(zhí)行時(shí)間和最小執(zhí)行時(shí)間等。這幾個方法在線程池里是空方法。
如:
protected void beforeExecute(Thread t, Runnable r) { }
以上為個人經(jīng)驗(yàn),希望能給大家一個參考,也希望大家多多支持腳本之家。如有錯誤或未考慮完全的地方,望不吝賜教。
相關(guān)文章
JAVA?ImageIO.read方法報(bào)錯/無效問題及解決
這篇文章主要介紹了JAVA?ImageIO.read方法報(bào)錯/無效問題及解決方案,具有很好的參考價(jià)值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2023-11-11詳解Java實(shí)現(xiàn)設(shè)計(jì)模式之責(zé)任鏈模式
責(zé)任鏈模式是一種行為設(shè)計(jì)模式,允許你將請求沿著處理鏈發(fā)送,然后處理者都可對其進(jìn)行處理,完成后可以再將其傳遞給下一個處理者。下面將會舉例說明什么是責(zé)任鏈模式,責(zé)任鏈模式該如何使用2021-06-06java 中模擬UDP傳輸?shù)陌l(fā)送端和接收端實(shí)例詳解
這篇文章主要介紹了java 中模擬UDP傳輸?shù)陌l(fā)送端和接收端實(shí)例詳解的相關(guān)資料,需要的朋友可以參考下2017-03-03Jmeter關(guān)聯(lián)實(shí)現(xiàn)及參數(shù)化使用解析
這篇文章主要介紹了Jmeter關(guān)聯(lián)實(shí)現(xiàn)及參數(shù)化使用解析,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-08-08