Java线程死锁–案例研究
此案例研究還將證明掌握線程轉(zhuǎn)儲分析技能的重要性; 包括用于IBM JVM Thread Dump格式。
環(huán)境規(guī)格
– Java EE服務(wù)器:Oracle Weblogic Server 11g和Spring 2.0.5 –操作系統(tǒng):AIX 5.3 – Java虛擬機(jī):IBM JRE 1.6.0 –平臺類型:門戶和訂購應(yīng)用程序
監(jiān)控和故障排除工具
– JVM線程轉(zhuǎn)儲(IBM JVM格式)– Compuware Server Vantage(Weblogic JMX監(jiān)視和警報(bào))
問題概述
從Compuware Server Vantage觀察到并報(bào)告了一個嚴(yán)重的線程阻塞問題,該問題影響了我們的2臺Weblogic 11g生產(chǎn)托管服務(wù)器,從而導(dǎo)致了最終用戶的應(yīng)用程序影響和超時情況。
事實(shí)的收集和驗(yàn)證
像往常一樣,Java EE問題調(diào)查需要收集技術(shù)和非技術(shù)事實(shí),因此我們可以得出其他事實(shí)和/或就根本原因進(jìn)行結(jié)論。 在采取糾正措施之前,要對以下事實(shí)進(jìn)行核實(shí),以便得出根本原因:
·對客戶有什么影響? MEDIUM(16個中只有2個受管服務(wù)器/ JVM受影響)·受影響平臺的最新更改? 是(新的與JMS相關(guān)的異步組件)·最近到受影響平臺的流量有增加嗎? 否·這個問題如何表現(xiàn)出來? 觀察到線程突然增加,導(dǎo)致線程快速耗盡。·Weblogic托管服務(wù)器重新啟動是否解決了問題? 是的,但是幾個小時后問題又回來了(不可預(yù)測的間歇性模式)
– 結(jié)論1 :
該問題與間歇性卡住的線程行為有關(guān),該行為當(dāng)時僅影響少數(shù)Weblogic托管服務(wù)器
– 結(jié)論2 :
由于問題是斷斷續(xù)續(xù)的,因此不太可能出現(xiàn)全局根本原因,例如下游系統(tǒng)無響應(yīng)
線程轉(zhuǎn)儲分析–第一遍
處理滯留的線程問題時,要做的第一件事是生成JVM線程轉(zhuǎn)儲。 無論您的環(huán)境規(guī)格和問題背景如何,這都是一條黃金法則。 JVM線程轉(zhuǎn)儲快照為您提供了有關(guān)活動線程及其當(dāng)時正在執(zhí)行的處理/任務(wù)類型的重要信息。
現(xiàn)在回到我們的案例研究,生成了一個IBM JVM線程轉(zhuǎn)儲(javacore.xyz格式),它確實(shí)揭示了以下Java線程死鎖情況:
死鎖情況可以按照以下方式進(jìn)行翻譯:
– Weblogic線程8正在等待獲取Weblogic線程10擁有的對象監(jiān)視器鎖
– Weblogic線程#10正在等待獲取Weblogic線程#8擁有的對象監(jiān)視器鎖 結(jié)論: Weblogic線程#8和#10都在等待。 永遠(yuǎn)! 現(xiàn)在,在深入分析根本原因之前,讓我為您提供有關(guān)Java Thread死鎖的高級概述。
Java線程死鎖概述
你們中的大多數(shù)人可能都熟悉Java Thread死鎖原理,但是您真的遇到了真正的死鎖問題嗎?
根據(jù)我的經(jīng)驗(yàn),真正的Java死鎖很少見,在過去的10年中,我只看到5次此類死鎖。 原因是大多數(shù)與線程卡住有關(guān)的問題是由于線程掛起情況(正在等待遠(yuǎn)程IO調(diào)用等)引起的,而與其他線程沒有真正的死鎖條件有關(guān)。
Java線程死鎖是一種情況,例如,線程A等待獲取線程B持有的對象監(jiān)視器鎖,而該線程本身正等待獲取線程A持有的對象監(jiān)視器鎖。這兩個線程將永遠(yuǎn)彼此等待。 這種情況可以如下圖所示:
線程死鎖已確認(rèn)……現(xiàn)在該怎么辦?
一旦確認(rèn)了死鎖( 大多數(shù)JVM線程轉(zhuǎn)儲實(shí)現(xiàn)將為您突出顯示 ),下一步就是通過檢查死鎖情況下涉及的每個線程及其當(dāng)前任務(wù)和等待條件,來進(jìn)行更深入的分析。
在我們的問題案例中,對于涉及死鎖條件的每個線程,在部分線程堆棧跟蹤下面找到: **請注意,出于保密目的,真實(shí)應(yīng)用程序Java包名稱已重命名**
Weblogic線程#8
'[STUCK] ExecuteThread: '8' for queue: 'weblogic.kernel.Default (self-tuning)'' J9VMThread:0x000000012CC08B00, j9thread_t:0x00000001299E5100, java/lang/Thread:0x070000001D72EE00, state:B, prio=1(native thread ID:0x111200F, native priority:0x1, native policy:UNKNOWN)Java callstack:at weblogic/jms/frontend/FEConnection.stop(FEConnection.java:671(Compiled Code))at weblogic/jms/frontend/FEConnection.invoke(FEConnection.java:1685(Compiled Code))at weblogic/messaging/dispatcher/Request.wrappedFiniteStateMachine(Request.java:961(Compiled Code))at weblogic/messaging/dispatcher/DispatcherImpl.syncRequest(DispatcherImpl.java:184(Compiled Code))at weblogic/messaging/dispatcher/DispatcherImpl.dispatchSync(DispatcherImpl.java:212(Compiled Code))at weblogic/jms/dispatcher/DispatcherAdapter.dispatchSync(DispatcherAdapter.java:43(Compiled Code))at weblogic/jms/client/JMSConnection.stop(JMSConnection.java:863(Compiled Code))at weblogic/jms/client/WLConnectionImpl.stop(WLConnectionImpl.java:843)at org/springframework/jms/connection/SingleConnectionFactory.closeConnection(SingleConnectionFactory.java:342)at org/springframework/jms/connection/SingleConnectionFactory.resetConnection (SingleConnectionFactory.java:296)at org/app/JMSReceiver.receive()……………………………………………………………………Weblogic線程#10
'[STUCK] ExecuteThread: '10' for queue: 'weblogic.kernel.Default (self-tuning)'' J9VMThread:0x000000012E560500, j9thread_t:0x000000012E35BCE0, java/lang/Thread:0x070000001ECA9200, state:B, prio=1(native thread ID:0x4FA027, native priority:0x1, native policy:UNKNOWN)Java callstack:at weblogic/jms/frontend/FEConnection .getPeerVersion(FEConnection.java:1381(Compiled Code))at weblogic/jms/frontend/FESession.setUpBackEndSession(FESession.java:755(Compiled Code))at weblogic/jms/frontend/FESession.consumerCreate(FESession.java:1025(Compiled Code))at weblogic/jms/frontend/FESession.invoke(FESession.java:2995(Compiled Code))at weblogic/messaging/dispatcher/Request.wrappedFiniteStateMachine(Request.java:961(Compiled Code))at weblogic/messaging/dispatcher/DispatcherImpl.syncRequest(DispatcherImpl.java:184(Compiled Code))at weblogic/messaging/dispatcher/DispatcherImpl.dispatchSync(DispatcherImpl.java:212(Compiled Code))at weblogic/jms/dispatcher/DispatcherAdapter.dispatchSync(DispatcherAdapter.java:43(Compiled Code))at weblogic/jms/client/JMSSession.consumerCreate(JMSSession.java:2982(Compiled Code))at weblogic/jms/client/JMSSession.setupConsumer(JMSSession.java:2749(Compiled Code))at weblogic/jms/client/JMSSession.createConsumer(JMSSession.java:2691(Compiled Code))at weblogic/jms/client/JMSSession.createReceiver(JMSSession.java:2596(Compiled Code))at weblogic/jms/client/WLSessionImpl.createReceiver(WLSessionImpl.java:991(Compiled Code))at org/springframework/jms/core/JmsTemplate102.createConsumer(JmsTemplate102.java:204(Compiled Code))at org/springframework/jms/core/JmsTemplate.doReceive(JmsTemplate.java:676(Compiled Code))at org/springframework/jms/core/JmsTemplate$10.doInJms(JmsTemplate.java:652(Compiled Code))at org/springframework/jms/core/JmsTemplate.execute(JmsTemplate.java:412(Compiled Code))at org/springframework/jms/core/JmsTemplate.receiveSelected(JmsTemplate.java:650(Compiled Code))at org/springframework/jms/core/JmsTemplate.receiveSelected(JmsTemplate.java:641(Compiled Code))at org/app/JMSReceiver.receive()…………………………………………………………… 如您在上面的“線程跟蹤跟蹤”中所看到的,這種死鎖確實(shí)來自我們的應(yīng)用程序代碼,該應(yīng)用程序代碼使用Spring框架API進(jìn)行JMS使用者實(shí)現(xiàn)(在不使用MDB的情況下非常有用)。 堆棧跟蹤非常有趣,它揭示了兩個線程都在與相同的 Weblogic JMS使用者會話/連接競爭的情況下,并導(dǎo)致死鎖情況:
– Weblogic線程#8試圖重置并關(guān)閉當(dāng)前的JMS連接– Weblogic線程#10試圖使用相同的JMS連接/會話以創(chuàng)建新的JMS使用方–觸發(fā)了線程死鎖!
根本原因:非線程安全的Spring JMS SingleConnectionFactory實(shí)現(xiàn)
Spring JIRA錯誤數(shù)據(jù)庫的代碼回顧和快速研究確實(shí)揭示了以下與上述分析完美相關(guān)的以下線程安全缺陷:
#SingleConnectionFactory的resetConnection導(dǎo)致與基礎(chǔ)OracleAQ的JMS連接的死鎖https://jira.springsource.org/browse/SPR-5987
Spring SingleConnectionFactory的修補(bǔ)程序于2009年發(fā)布,確實(shí)涉及添加適當(dāng)?shù)膕ync {}塊,以防止在發(fā)生JMS Connection重置操作時線程死鎖:
解
我們的團(tuán)隊(duì)目前正計(jì)劃將該Spring補(bǔ)丁不久后集成到我們的生產(chǎn)環(huán)境中。 在我們的測試環(huán)境中執(zhí)行的初始測試是肯定的。
結(jié)論
我希望這個案例研究能幫助您理解現(xiàn)實(shí)中的Java線程死鎖問題,以及適當(dāng)?shù)木€程轉(zhuǎn)儲分析技能如何使您能夠在代碼級快速查明與線程相關(guān)的卡住問題的根本原因。 請不要猶豫,發(fā)表任何評論或問題。
參考: Java Thread死鎖–來自我們的JCG合作伙伴 Pierre-Hugues Charbonneau的案例研究 ,位于Java EE支持模式和Java教程博客上。
翻譯自: https://www.javacodegeeks.com/2012/06/java-thread-deadlock-case-study.html
總結(jié)
以上是生活随笔為你收集整理的Java线程死锁–案例研究的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 代理ip攻击(ip代理防止ddos)
- 下一篇: BTrace for Java应用程序简