什麼是死結
死結:兩個或多個動作一直在等待其他動作的完成而使得所有動作都始終處於阻塞的狀態。
開發階段檢測死結很困難;測試階段也很困難-死結通常發生在負載嚴重的情況下。解除死結往往需要重啟程式。
儘管有些靜態分析庫可以協助我們發現可能出現的死結,但還是有必須在運行時檢測到死結,得到資訊,以便我們解決問題或重啟。 產生死結的例子
如圖:
利用JConsole排查死結
JConsole是一個基於JMX的GUI工具,用於串連正在啟動並執行JVM,不過此JVM需要使用可管理的模式啟動。
通過JConsole可以查看當前所有線程所處的狀態,如圖:
利用Jstack排查死結
jstack用於產生java虛擬機器當前時刻的線程快照。線程快照是當前java虛擬機器內每一條線程正在執行的方法堆棧的集合,產生線程快照的主要目的是定位線程出現長時間停頓的原因,如線程間死結、死迴圈、請求外部資源導致的長時間等待等。
線程出現停頓的時候通過jstack來查看各個線程的呼叫堆疊,就可以知道沒有響應的線程到底在後台做什麼事情,或者等待什麼資源。
通過Jstack命令 Jstack -l 進程號 查看死結,如圖:
利用ThreadMXBean排查死結
前面所介紹的都是利用程式外部的JVM監控管理工具進行死結排查,那麼如果希望實現代碼中自動探索死結並作出響應(例如重啟服務等)應當怎麼做呢。我們可以利用ThreadMXBean。
Java 5引入了ThreadMXBean介面,它提供了多種監視線程的方法。我建議您瞭解所有這些方法,因為當您沒使用外部工具時,它們會為您提供很多有用的操作以便您監測程式效能。
重要方法:findDeadlockedThreads(Java 6); findMonitorDeadlockedThreads (java 5)。(二者的區別的是,findDeadlockedThreads還可以檢測到owner locks(java.util.concurrent)引起的死結,而findMonitorDeadlockedThreads只能檢測monitor locks(例如,同步塊)。) 首先編寫一個檢測死結的類,需要用到調度介面每隔一段時間執行一次:
編寫一個處理死結的類,這裡只做輸出:
修改main方法:
執行結果如圖:
通過結果能夠很好的看出每個線程等待哪個鎖,這個鎖被哪個線程持有。
在這個介面的注釋上有這麼兩行:
說明這個方法對系統的開銷還是比較大的,所以對於調度的頻率需要根據具體情況謹慎考慮。