java定位死鎖的三種方法(jstack、Arthas和Jvisualvm)
死鎖
死鎖:是指兩個或兩個以上的進(jìn)程在執(zhí)行過程中,因爭奪資源而造成的一種互相等待的現(xiàn)象,若無外力作用,它們都將無法推進(jìn)下去。
死鎖發(fā)生的原因
死鎖的發(fā)生是由于資源競爭導(dǎo)致的,導(dǎo)致死鎖的原因如下:
- 系統(tǒng)資源不足,如果系統(tǒng)資源充足,死鎖出現(xiàn)的可能性就很低。
- 進(jìn)程(線程)運(yùn)行推進(jìn)的順序不合適。
- 資源分配不當(dāng)?shù)取?br />
死鎖發(fā)生的條件
死鎖的發(fā)生的四個必要條件:
- 互斥條件:一個資源每次只能被一個進(jìn)程使用。
- 占有且等待:一個進(jìn)程因請求資源而阻塞時,對已獲得的資源保持不放。
- 不可強(qiáng)行占有:進(jìn)程(線程)已獲得的資源,在未使用完之前,不能強(qiáng)行剝奪。
- 循環(huán)等待條件:若干進(jìn)程(線程)之間形成一種頭尾相接的循環(huán)等待資源關(guān)系。
這四個條件是死鎖的必要條件,只要系統(tǒng)發(fā)生死鎖,這些條件必然成立,而只要上述條件之一不滿足,就不會發(fā)生死鎖。
1:通過jstack定位死鎖信息
1.1:編寫死鎖代碼
Lock lock1 = new ReentrantLock();
Lock lock2 = new ReentrantLock();
ExecutorService exectuorService = Executors.newFixedThreadPool(2);
exectuorService.submit(() -> {
lock1.lock();
try{
Thread.sleep(1000);
}catch(Exception e){}
try{}
finally{
lock1.unlock();
lock2.unlock();
}
});
exectuorService.submit(() -> {
lock2.lock();
try{
Thread.sleep(1000);
}catch(Exception e){}
try{}
finally{
lock1.unlock();
lock2.unlock();
}
});
1.2:查看死鎖線程的pid
- jps查看死鎖的線程pid
- 使用 jstack -l pid 查看死鎖信息
- 通過打印信息我們可以找到發(fā)生死鎖的代碼是在哪個位置
"DestroyJavaVM" #13 prio=5 os_prio=31 tid=0x00007f9a1d8fe800 nid=0xd03 waiting on condition [0x0000000000000000] java.lang.Thread.State: RUNNABLE Locked ownable synchronizers: - None "pool-1-thread-2" #12 prio=5 os_prio=31 tid=0x00007f9a1d8fe000 nid=0xa703 waiting on condition [0x000070000ff8e000] java.lang.Thread.State: WAITING (parking) at sun.misc.Unsafe.park(Native Method) - parking to wait for <0x0000000795768cd8> (a java.util.concurrent.locks.ReentrantLock$NonfairSync) at java.util.concurrent.locks.LockSupport.park(LockSupport.java:175) at java.util.concurrent.locks.AbstractQueuedSynchronizer.parkAndCheckInterrupt(AbstractQueuedSynchronizer.java:836) at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquireQueued(AbstractQueuedSynchronizer.java:870) at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquire(AbstractQueuedSynchronizer.java:1199) at java.util.concurrent.locks.ReentrantLock$NonfairSync.lock(ReentrantLock.java:209) at java.util.concurrent.locks.ReentrantLock.lock(ReentrantLock.java:285) at com.coco.util.SlideTimeUnit.lambda$main$1(SlideTimeUnit.java:63) at com.coco.util.SlideTimeUnit$$Lambda$2/565760380.run(Unknown Source) at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511) at java.util.concurrent.FutureTask.run(FutureTask.java:266) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) at java.lang.Thread.run(Thread.java:748) Locked ownable synchronizers: - <0x0000000795768d08> (a java.util.concurrent.locks.ReentrantLock$NonfairSync) - <0x0000000795a9e4e0> (a java.util.concurrent.ThreadPoolExecutor$Worker) "pool-1-thread-1" #11 prio=5 os_prio=31 tid=0x00007f9a2082c800 nid=0xa803 waiting on condition [0x000070000fe8b000] java.lang.Thread.State: WAITING (parking) at sun.misc.Unsafe.park(Native Method) - parking to wait for <0x0000000795768d08> (a java.util.concurrent.locks.ReentrantLock$NonfairSync) at java.util.concurrent.locks.LockSupport.park(LockSupport.java:175) at java.util.concurrent.locks.AbstractQueuedSynchronizer.parkAndCheckInterrupt(AbstractQueuedSynchronizer.java:836) at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquireQueued(AbstractQueuedSynchronizer.java:870) at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquire(AbstractQueuedSynchronizer.java:1199) at java.util.concurrent.locks.ReentrantLock$NonfairSync.lock(ReentrantLock.java:209) at java.util.concurrent.locks.ReentrantLock.lock(ReentrantLock.java:285) at com.coco.util.SlideTimeUnit.lambda$main$0(SlideTimeUnit.java:49) at com.coco.util.SlideTimeUnit$$Lambda$1/596512129.run(Unknown Source) at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511) at java.util.concurrent.FutureTask.run(FutureTask.java:266) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) at java.lang.Thread.run(Thread.java:748) Locked ownable synchronizers: - <0x0000000795768cd8> (a java.util.concurrent.locks.ReentrantLock$NonfairSync) - <0x0000000795a9ba28> (a java.util.concurrent.ThreadPoolExecutor$Worker) "Service Thread" #10 daemon prio=9 os_prio=31 tid=0x00007f9a2082c000 nid=0x4103 runnable [0x0000000000000000] java.lang.Thread.State: RUNNABLE Locked ownable synchronizers: - None "C1 CompilerThread3" #9 daemon prio=9 os_prio=31 tid=0x00007f9a1e021800 nid=0x3f03 waiting on condition [0x0000000000000000] java.lang.Thread.State: RUNNABLE
2:通過Arthas工具定位死鎖
2.1: 下載好Arthas的jar,然后運(yùn)行
有一個 thread -b 就可以查看到死鎖信息
[arthas@4182]$ thread -b "pool-1-thread-2" Id=12 WAITING on java.util.concurrent.locks.ReentrantLock$NonfairSync@2cb8a9a3 owned by "pool-1-thread-1" Id=11 at sun.misc.Unsafe.park(Native Method) - waiting on java.util.concurrent.locks.ReentrantLock$NonfairSync@2cb8a9a3 at java.util.concurrent.locks.LockSupport.park(LockSupport.java:175) at java.util.concurrent.locks.AbstractQueuedSynchronizer.parkAndCheckInterrupt(AbstractQueuedSynchronizer.java:836) at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquireQueued(AbstractQueuedSynchronizer.java:870) at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquire(AbstractQueuedSynchronizer.java:1199) at java.util.concurrent.locks.ReentrantLock$NonfairSync.lock(ReentrantLock.java:209) at java.util.concurrent.locks.ReentrantLock.lock(ReentrantLock.java:285) at com.coco.util.SlideTimeUnit.lambda$main$1(SlideTimeUnit.java:63) at com.coco.util.SlideTimeUnit$$Lambda$2/565760380.run(Unknown Source) at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511) at java.util.concurrent.FutureTask.run(FutureTask.java:266) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) at java.lang.Thread.run(Thread.java:748) Number of locked synchronizers = 2 - java.util.concurrent.ThreadPoolExecutor$Worker@6433a2 - java.util.concurrent.locks.ReentrantLock$NonfairSync@3a855d13 <---- but blocks 1 other threads!
3. 通過 Jvisualvm 定位死鎖
Jvisualvm 是一種自帶的可視化工具,往往在在本地執(zhí)行。
通過 Jvisualvm 命令打開軟件,選中進(jìn)程,進(jìn)入線程視圖,會給出死鎖提示:

死鎖的預(yù)防
- 盡量避免使用多個鎖,并且只有需要時才持有鎖。
- 如果使用多個鎖,一定要設(shè)計(jì)好鎖的獲取順序。
- 使用帶有超時的方法,為程序帶來更多的可控性,比如指定獲取鎖的時間最多為5秒,超時就放棄。
- 通過一些代碼靜態(tài)檢查工具發(fā)現(xiàn)可能存在的死鎖問題,比如FindBugs。
總結(jié)
到此這篇關(guān)于java定位死鎖的文章就介紹到這了,更多相關(guān)java定位死鎖內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
java開發(fā)建造者模式驗(yàn)證實(shí)例詳解
這篇文章主要為大家介紹了java開發(fā)中建造者模式的驗(yàn)證實(shí)例詳解,文中附含詳細(xì)示例代碼,有需要的朋友可以借鑒參考下,希望能夠有所幫助2021-10-10
java?mybatis如何操作postgresql?array數(shù)組類型
這篇文章主要介紹了java?mybatis如何操作postgresql?array數(shù)組類型,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-01-01
如何解決UnsupportedOperationException異常問題
這篇文章主要介紹了如何解決UnsupportedOperationException異常問題,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2023-05-05
Spring Security獲取用戶認(rèn)證信息的實(shí)現(xiàn)流程
Spring Security是一個能夠?yàn)榛赟pring的企業(yè)應(yīng)用系統(tǒng)提供聲明式的安全訪問控制解決方案的安全框架。它提供了一組可以在Spring應(yīng)用上下文中配置的Bean,充分利用了Spring IoC,DI和AOP功能,為應(yīng)用系統(tǒng)提供聲明式的安全訪問控制功能2022-12-12

