Java死锁故障排除和解决
JavaOne年度會(huì)議的一大優(yōu)點(diǎn)是,主題專家介紹了幾個(gè)技術(shù)和故障排除實(shí)驗(yàn)室。 其中的一個(gè)實(shí)驗(yàn)室今年特別吸引了我的注意力:“ HOL6500-查找和解決Java死鎖 ”,由Java冠軍Heinz Kabutz提出 。 這是我在該主題上看到的最好的演示之一。 我建議您自己下載,運(yùn)行和研究實(shí)驗(yàn)室。
本文將重溫這個(gè)經(jīng)典的線程問(wèn)題,并總結(jié)提出的關(guān)鍵故障排除和解決方法。 我還將根據(jù)自己的多線程故障排除經(jīng)驗(yàn)來(lái)擴(kuò)展主題。
Java死鎖:這是什么?
真正的Java死鎖本質(zhì)上可以描述為兩個(gè)或多個(gè)線程永遠(yuǎn)被阻塞,互相等待的情況。 這種情況與其他更常見的“日常”線程問(wèn)題模式(例如鎖爭(zhēng)用和線程爭(zhēng)用,等待阻塞IO調(diào)用的線程等)截然不同。這種鎖排序死鎖情況可以如下所示:
在上面的可視示例中,線程A和線程B嘗試以不同順序獲取2個(gè)鎖是致命的。 一旦線程達(dá)到死鎖狀態(tài),它們將永遠(yuǎn)無(wú)法恢復(fù),從而迫使您重新啟動(dòng)受影響的JVM進(jìn)程。
Heinz還描述了另一種死鎖: 資源死鎖 。 到目前為止,這是我在Java EE企業(yè)系統(tǒng)故障排除經(jīng)驗(yàn)中最常見的線程問(wèn)題模式。 資源死鎖本質(zhì)上是一種場(chǎng)景,其中一個(gè)或多個(gè)線程正在等待獲取永遠(yuǎn)無(wú)法使用的資源,例如JDBC池耗盡。
鎖排序死鎖
您現(xiàn)在應(yīng)該知道我是JVM線程轉(zhuǎn)儲(chǔ)分析的忠實(shí)擁護(hù)者 ; 對(duì)于參與Java / Java EE開發(fā)或生產(chǎn)支持的個(gè)人而言至關(guān)重要的技能。 好消息是,大多數(shù)JVM線程轉(zhuǎn)儲(chǔ)格式(HotSpot,IBM VM…)都可以很容易地對(duì)Java級(jí)別的死鎖進(jìn)行開箱即用的識(shí)別,因?yàn)樗鼈儼緳C(jī)死鎖檢測(cè)機(jī)制,該機(jī)制實(shí)際上將向您顯示所涉及的線程。真正的Java級(jí)死鎖場(chǎng)景以及執(zhí)行堆棧跟蹤。 可以通過(guò)您選擇的工具(例如JVisualVM,jstack或本機(jī)例如基于Unix的操作系統(tǒng)上的kill -3 <PID>)捕獲JVM線程轉(zhuǎn)儲(chǔ)。 在運(yùn)行實(shí)驗(yàn)1之后,在JVM Java級(jí)死鎖檢測(cè)部分下面找到:
現(xiàn)在,這是簡(jiǎn)單的部分……根本原因分析工作的核心是首先了解為什么此類線程涉及死鎖情況。 鎖順序死鎖可能會(huì)從您的應(yīng)用程序代碼中觸發(fā),但是除非您參與高并發(fā)性編程,否則,可能的罪魁禍?zhǔn)资悄谑褂玫牡谌紸PI或框架或?qū)嶋H的Java EE容器本身(如果適用)。
現(xiàn)在讓我們?cè)谙旅婊仡櫼幌潞嗍咸岢龅逆i排序死鎖解決策略:
#通過(guò)全局排序解決死鎖(請(qǐng)參閱lab1解決方案)
- 本質(zhì)上涉及對(duì)鎖的全局排序的定義,它將始終防止死鎖(請(qǐng)參閱lab1解決方案)
#TryLock解決死鎖(請(qǐng)參閱lab2解決方案)
- 鎖定第一把鎖
- 然后嘗試鎖定第二把鎖
- 如果您可以鎖定它,那就很好了
- 如果不能,請(qǐng)?jiān)僭囈淮?
可以使用Java Lock&ReantrantLock來(lái)實(shí)現(xiàn)上述策略,這也使您能夠靈活地設(shè)置等待超時(shí),以防止在第一個(gè)鎖獲取時(shí)間太長(zhǎng)的情況下導(dǎo)致線程不足。
public interface Lock {void lock();void lockInterruptibly() throws InterruptedException;boolean tryLock();boolean tryLock(long timeout, TimeUnit unit)throws InterruptedException;void unlock();Condition newCondition();}如果查看JBoss AS7實(shí)現(xiàn),您會(huì)注意到Lock&ReantrantLock在核心實(shí)現(xiàn)層中得到了廣泛使用,例如:
- 部署服務(wù)
- EJB3實(shí)現(xiàn)(廣泛使用)
- 集群和會(huì)話管理
- 內(nèi)部緩存和數(shù)據(jù)結(jié)構(gòu)(LRU,ConcurrentReferenceHashMap…)
現(xiàn)在,按照亨氏的觀點(diǎn),死鎖解決方案#2可能非常有效,但也需要采取適當(dāng)?shù)拇胧?#xff0c;例如通過(guò)finally {}塊釋放所有持有的鎖,否則您可以將死鎖方案轉(zhuǎn)換為活動(dòng)鎖 。
資源僵局
現(xiàn)在,讓我們轉(zhuǎn)到資源死鎖場(chǎng)景。 我很高興Heinz的實(shí)驗(yàn)室#3涵蓋了這一點(diǎn),因?yàn)楦鶕?jù)我的經(jīng)驗(yàn),這是迄今為止您將看到的最常見的“死鎖”場(chǎng)景,尤其是在開發(fā)和支持大型分布式Java EE生產(chǎn)系統(tǒng)時(shí)。
現(xiàn)在,讓我們弄清事實(shí)。
- 資源死鎖不是真正的Java級(jí)死鎖
- 如果您遇到這些類型的死鎖,那么JVM線程轉(zhuǎn)儲(chǔ)將不會(huì)神奇。 這意味著您需要做更多工作來(lái)分析和理解此問(wèn)題作為起點(diǎn)。
- 當(dāng)您剛開始學(xué)習(xí)如何讀取線程轉(zhuǎn)儲(chǔ)時(shí),線程轉(zhuǎn)儲(chǔ)分析可能會(huì)特別令人困惑,因?yàn)閷?duì)于Java級(jí)死鎖,線程通常會(huì)顯示為RUNNING狀態(tài)還是BLOCKED狀態(tài)。 現(xiàn)在,重要的是要記住線程狀態(tài)對(duì)于這種類型的問(wèn)題不是那么重要,例如RUNNING state!= Healthy state。
- 分析方法與Java級(jí)別的死鎖非常不同。 您必須創(chuàng)建多個(gè)線程轉(zhuǎn)儲(chǔ)快照,并確定每個(gè)快照之間的線程問(wèn)題/等待模式。 您將能夠看到線程沒有移動(dòng),例如等待從池中獲取資源的線程以及已經(jīng)獲取該資源并掛起的其他線程。
- 線程轉(zhuǎn)儲(chǔ)分析不是這里重要的唯一數(shù)據(jù)點(diǎn)/事實(shí)。 您將需要收集其他事實(shí),例如有關(guān)線程正在等待的資源,整體中間件或環(huán)境運(yùn)行狀況等的統(tǒng)計(jì)信息。所有這些事實(shí)的結(jié)合將使您能夠得出根本原因以及解決策略的結(jié)論,或可能不涉及代碼更改。
我將以更多的線程轉(zhuǎn)儲(chǔ)問(wèn)題模式與您聯(lián)系,但首先請(qǐng)確保您對(duì)JVM線程轉(zhuǎn)儲(chǔ)的基本原理感到滿意。
結(jié)論
我希望您像我一樣有機(jī)會(huì)回顧,運(yùn)行和享受亨氏演講中的實(shí)驗(yàn)室。 并發(fā)編程和故障排除可能會(huì)非常具有挑戰(zhàn)性,但是我仍然建議您花一些時(shí)間來(lái)理解其中一些原則,因?yàn)槲蚁嘈拍鷷?huì)在不久的將來(lái)遇到某種情況,這將迫使您進(jìn)行這種深入研究并掌握這些原則。技能。
參考: Java EE支持模式和Java教程博客中的JCG合作伙伴 Pierre-Hugues Charbonneau提供的Java死鎖故障排除和解決方法 。
翻譯自: https://www.javacodegeeks.com/2012/11/java-deadlock-troubleshooting-and-resolution.html
總結(jié)
以上是生活随笔為你收集整理的Java死锁故障排除和解决的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: ddos 路由器(ddos路由器ip地址
- 下一篇: 深圳环境备案平台(深圳环境备案)