工欲善其事,必先利其器
簡介
本篇整理兩個排查問題的簡單技巧,一個是java死鎖排查,這個一般在面試的時會問到,如果沒有寫多線程的話,實際中遇到的機會不多;第二個是java cpu 100%排查,這個實際的開發中,線的應用出現這個問題可能性比較大,所以這里簡單總結介紹一下,對自己學習知識的一個整理,提高自己的解決問題能力。
一、Java死鎖排查
通過標題我們就要思考三個問題:
- 什么是死鎖?
- 為什么會出現死鎖?
- 怎么排查代碼中出現了死鎖?
作為技術人員(工程師),在面對問題的時候,可能需要的能力是怎么去解決這個問題。但是在學習技術知識的時候,那就要多問為什么,一定要鍛煉自己這方面的能力,這樣才能更好的掌握知識。
解答:
-
什么是死鎖?
死鎖是指兩個或兩個以上的進程在執行過程中,由於競爭資源或者由於彼此通信而造成的一種阻塞的現象,若無外力作用,它們都將無法推進下去。此時稱系統處於死鎖狀態或系統產生了死鎖,這些永遠在互相等待的進程稱為死鎖進程。百度百科:死鎖
注:進程和線程都可以發生死鎖,只要滿足死鎖的條件!
-
為什么會出現死鎖?
從上面的概念中我們知道
(1)必須是兩個或者兩個以上進程(線程)
(2)必須有競爭資源 -
怎么排查代碼中出現了死鎖?【重點來了】
首先寫一個死鎖的代碼,看例子:
/** * * 使用jstack 排查死鎖 * @author dufyun * */ public class JStackDemo { public static void main(String[] args) { Thread t1 = new Thread(new DeadLockTest(true));//建立一個線程 Thread t2 = new Thread(new DeadLockTest(false));//建立另一個線程 t1.setName("thread-dufy-1"); t2.setName("thread-dufy-2"); t1.start();//啟動一個線程 t2.start();//啟動另一個線程 } } class DeadLockTest implements Runnable { public boolean falg;// 控制線程 DeadLockTest(boolean falg) { this.falg = falg; } public void run() { /** * 如果falg的值為true則調用t1線程 */ if (falg) { while (true) { synchronized (Demo.o1) { System.out.println("o1 " + Thread.currentThread().getName()); synchronized (Demo.o2) { System.out.println("o2 " + Thread.currentThread().getName()); } } } } /** * 如果falg的值為false則調用t2線程 */ else { while (true) { synchronized (Demo.o2) { System.out.println("o2 " + Thread.currentThread().getName()); synchronized (Demo.o1) { System.out.println("o1 " + Thread.currentThread().getName()); } } } } } } class Demo { static Object o1 = new Object(); static Object o2 = new Object(); }
上面這段代碼執行后,就會出現死鎖,那么排查的方法有如下:
使用 jps + jstack
第一:在windons命令窗口,使用 jps -l 【不會使用jps請自行查詢資料】
第二:使用jstack -l 12316 【不會使用jstack請自行查詢資料】
使用jconsole
在window打開 JConsole,JConsole是一個圖形化的監控工具!
在windons命令窗口 ,輸出 JConsole
使用Java Visual VM
在window打開 jvisualvm,jvisualvm是一個圖形化的監控工具!
在windons命令窗口 ,輸出 jvisualvm
二、Java CPU 100% 排查
這個如果在實際的應用開發中遇到,要怎么排查呢?
這里沒有一步步的圖示過程,只有一個簡單的操作過程!有空寫一個詳細的例子。
1 、 使用top命令查看cpu占用資源較高的PID
2、 通過jps 找到當前用戶下的java程序PID
執行 jps -l 能夠打印出所有的應用的PID,找到有一個PID和這個cpu使用100%一樣的ID!!就知道是哪一個服務了。
3、 使用 pidstat -p 1 3 -u -t
4 、 找到cpu占用較高的線程TID
通過上圖發現是 3467的TID占用cup較大
5、 將TID轉換為十六進制的表示方式
將3467轉為十六進制 d8d,注意是小寫!
6、 通過jstack -l 輸出當前進程的線程信息
使用jstack 輸出當前PID的線程dunp信息
7、 查找 TID對應的線程(輸出的線程id為十六進制),找到對應的代碼
三、壓力測試使用jstack找到系統的代碼性能問題
1、在進行壓力測試的時候,使用jps找到應用的PID
2、然后使用jstack輸出出壓力測試時候應用的dump信息
3、分析輸出的日志文件中那個方法block線程占用最多,這里可能是性能有問題,找到對應的代碼分析
參考
1、Java應用CPU占用100%原因分析
2、[Java] CPU 100% 原因查找解決
3、線上應用故障排查系列
4、分析JAVA應用CPU占用過高的問題