JVM 線程分析

使用

導(dǎo)出線程堆棧:jstack? pid > c:/file.txt

線程狀態(tài)

Java官方定義的線程狀態(tài)有6種蛹批,定義在一個(gè)枚舉類中:

NEW,未啟動的線程第租,不會出現(xiàn)在Dump中措拇;

RUNNABLE,運(yùn)行中慎宾,包括就緒狀態(tài)和運(yùn)行中狀態(tài)丐吓, 調(diào)用start方法并獲取到鎖后進(jìn)入就緒狀態(tài),獲取到CPU后進(jìn)入運(yùn)行中狀態(tài)趟据;(當(dāng)線程遇到I/O或者調(diào)用suspend掛起線程時(shí)還是在運(yùn)行狀態(tài))券犁;

BLOCKED,受阻塞并等待監(jiān)視器鎖汹碱,被某個(gè)鎖(synchronizers)給block住了粘衬;

WATING,無限期等待某個(gè)condition或monitor發(fā)生咳促,一般停留在park, wait,?sleep,join (未設(shè)置超時(shí)時(shí)間)等語句里稚新;

TIMED_WATING,有時(shí)限的等待另一個(gè)線程的特定操作跪腹,如sleep褂删,加上超時(shí)時(shí)間的wait;

TERMINATED,已退出的冲茸。

堆棧信息中不存在NEW和TERMINATED狀態(tài)屯阀。

監(jiān)視器(Monitor)

Monitor是用以實(shí)現(xiàn)線程之間的互斥與協(xié)作的主要手段缅帘,它可以看成是對象或者 Class的鎖。每一個(gè)對象都有难衰,也僅有一個(gè) monitor钦无。

Monitor可以類比為一個(gè)特殊的房間,這個(gè)房間中有一些被保護(hù)的數(shù)據(jù)盖袭,Monitor保證每次只能有一個(gè)線程能進(jìn)入這個(gè)房間進(jìn)行訪問被保護(hù)的數(shù)據(jù)失暂,進(jìn)入房間即為持有Monitor,退出房間即為釋放Monitor苍凛。

當(dāng)一個(gè)線程需要訪問受保護(hù)的數(shù)據(jù)(即需要獲取對象的Monitor)時(shí)趣席,它會首先在entry-set入口隊(duì)列中排隊(duì)(這里并不是真正的按照排隊(duì)順序),如果沒有其他線程正在持有對象的Monitor醇蝴,那么它會和entry-set隊(duì)列和wait-set隊(duì)列中的被喚醒的其他線程進(jìn)行競爭(即通過CPU調(diào)度)宣肚,選出一個(gè)線程來獲取對象的Monitor,執(zhí)行受保護(hù)的代碼段悠栓,執(zhí)行完畢后釋放Monitor霉涨,如果已經(jīng)有線程持有對象的Monitor,那么需要等待其釋放Monitor后再進(jìn)行競爭惭适。

再說一下wait-set隊(duì)列笙瑟。當(dāng)一個(gè)線程擁有Monitor后,經(jīng)過某些條件的判斷(比如用戶取錢發(fā)現(xiàn)賬戶沒錢)癞志,這個(gè)時(shí)候需要調(diào)用Object的wait方法往枷,線程就釋放了Monitor,進(jìn)入wait-set隊(duì)列凄杯,等待Object的notify方法(比如用戶向賬戶里面存錢)错洁。當(dāng)該對象調(diào)用了notify方法或者notifyAll方法后,wait-set中的線程就會被喚醒戒突,然后在wait-set隊(duì)列中被喚醒的線程和entry-set隊(duì)列中的線程一起通過CPU調(diào)度來競爭對象的Monitor屯碴,最終只有一個(gè)線程能獲取對象的Monitor。


進(jìn)入?yún)^(qū)(Entry Set):表示線程通過synchronized要求獲取對象的鎖膊存。如果對象未被鎖住导而,則進(jìn)入擁有者,否則在進(jìn)入?yún)^(qū)等待隔崎;

擁有者(The Owner):表示某一線程成功競爭到對象鎖今艺;

等待區(qū)(Wait Set):表示線程通過對象的wait方法,釋放對象的鎖爵卒,并在等待區(qū)等待被喚醒虚缎;


一個(gè) Monitor在某個(gè)時(shí)刻,只能被一個(gè)線程擁有技潘,該線程就是“Active Thread”遥巴,而其它線程都是“Waiting Thread”,分別在兩個(gè)隊(duì)列“ Entry Set”和“Wait Set”里面等候享幽;

在“Entry Set”中等待的線程狀態(tài)是“Waiting for monitor entry”铲掐,而在“Wait Set”中等待的線程狀態(tài)是“in Object.wait()”;?

我們稱被 synchronized保護(hù)起來的代碼段為臨界區(qū)值桩,當(dāng)一個(gè)線程申請進(jìn)入臨界區(qū)時(shí)摆霉,它就進(jìn)入了 “Entry Set”隊(duì)列;

線程堆棧解釋

線程名稱:若未設(shè)置奔坟,自動命名"thread-x" 或 "線程池名稱-thread-x"携栋,線程池若未設(shè)置,自動命名"pool-x"咳秉,若是守護(hù)線程后面會顯示“daemon”婉支;

線程優(yōu)先級:最低1,最高10澜建,默認(rèn)5向挖,優(yōu)先級高的不一定先執(zhí)行;

nid:tid映射的操作系統(tǒng)中的線程id炕舵,這里是用16進(jìn)制的表示何之;

線程動作(本地線程狀態(tài)):線程狀態(tài)產(chǎn)生的原因

---runnable:此時(shí)線程狀態(tài)一般為RUNNABLE;

---in Object.wait():等待區(qū)等待咽筋,此時(shí)線程狀態(tài)為WAITING或TIMED_WAITING溶推;

---waiting for monitor entry:進(jìn)入?yún)^(qū)等待,等待進(jìn)入一個(gè)臨界區(qū)奸攻,所以它在”Entry Set“隊(duì)列中等待蒜危,線程狀態(tài)一般是 BLOCKED;

---waiting on condition:等待區(qū)等待舞箍、被park舰褪,等待另一個(gè)條件的發(fā)生來把自己喚醒,線程狀態(tài)是:WAITING(parking疏橄,一直等那個(gè)條件發(fā)生)或 TIMED_WAITING?(parking或sleeping占拍,定時(shí)的,那個(gè)條件不到來捎迫,也將定時(shí)喚醒自己)晃酒;

---sleeping:休眠的線程,調(diào)用了Thread.sleep()窄绒;

調(diào)用修飾:表示線程在方法調(diào)用時(shí)贝次,額外的重要的操作

---locked <地址/鎖ID> 目標(biāo):使用synchronized申請對象鎖成功,監(jiān)視器的擁有者彰导;

---waiting to lock <地址/鎖ID> 目標(biāo):使用synchronized申請對象鎖未成功蛔翅,在進(jìn)入?yún)^(qū)等待敲茄;

---waiting on <地址/鎖ID> 目標(biāo):使用synchronized申請對象鎖成功后,釋放鎖在等待區(qū)等待山析;

---parking to wait for <地址/鎖ID> 目標(biāo):park是基本的線程阻塞原語堰燎,不通過監(jiān)視器在對象上阻塞,與synchronized體系不同笋轨;

尖括號中表示鎖ID秆剪,這個(gè)是系統(tǒng)自動產(chǎn)生的,我們只需要知道每次打印的堆棧爵政,同一個(gè)ID表示是同一個(gè)鎖即可仅讽。

---當(dāng)一個(gè)線程占有一個(gè)鎖的時(shí)候,線程的堆棧中會打印--locked<0x00000000d77d50c8>

---當(dāng)一個(gè)線程正在等待其它線程釋放該鎖钾挟,線程堆棧中會打印--waiting to lock<0x00000000d77d50c8>

---當(dāng)一個(gè)線程占有一個(gè)鎖洁灵,但又執(zhí)行到該鎖的wait()方法上,線程堆棧中首先打印locked掺出,然后又會打印--waiting on <0x00000000d77d50c8>


問題分析

大量線程在waiting for monitor entry

可能是一個(gè)全局鎖阻塞住了大量線程处渣,隨著時(shí)間流逝,waiting for monitor entry 的線程越來越多蛛砰,沒有減少的趨勢罐栈,可能意味著某些線程在臨界區(qū)里呆的時(shí)間太長了,以至于越來越多新線程遲遲無法進(jìn)入臨界區(qū)泥畅;

大量線程在waiting on condition

可能是它們又跑去獲取第三方資源荠诬,尤其是第三方網(wǎng)絡(luò)資源,遲遲獲取不到Response位仁,導(dǎo)致大量線程進(jìn)入等待狀態(tài)柑贞,所以如果你發(fā)現(xiàn)有大量的線程都處在 Wait on condition,從線程堆椖羟溃看钧嘶,正等待網(wǎng)絡(luò)讀寫,這可能是一個(gè)網(wǎng)絡(luò)瓶頸的征兆琳疏,因?yàn)榫W(wǎng)絡(luò)阻塞導(dǎo)致線程無法執(zhí)行有决;

線程在in Object.wait()

當(dāng)線程獲得了 Monitor,如果發(fā)現(xiàn)線程繼續(xù)運(yùn)行的條件沒有滿足空盼,它則調(diào)用對象的 wait() 方法书幕,放棄了 Monitor,進(jìn)入 “Wait Set”隊(duì)列揽趾,一般都是RMI相關(guān)線程(RMI RenewClean台汇、 GC Daemon、RMI Reaper),GC線程(Finalizer)苟呐,引用對象垃圾回收線程(Reference Handler)等系統(tǒng)線程處于這種狀態(tài)痒芝;

線程處于parking to wait for ?<>?(a java.util.concurrent.SynchronousQueue$TransferStack)

首先,本線程肯定是在等待某個(gè)條件的發(fā)生牵素,來把自己喚醒吼野。其次,SynchronousQueue 并不是一個(gè)隊(duì)列两波,只是線程之間移交信息的機(jī)制,當(dāng)我們把一個(gè)元素放入到 SynchronousQueue 中時(shí)必須有另一個(gè)線程正在等待接受移交的任務(wù)闷哆,因此這就是本線程在等待的條件腰奋。

CPU占用率很高,響應(yīng)很慢

先找到占用CPU的進(jìn)程抱怔,然后再定位到對應(yīng)的線程劣坊,最后分析出對應(yīng)的堆棧信息。

Linux環(huán)境下屈留,使用 top -Hp pid 可以查看進(jìn)程下各個(gè)線程的cpu 內(nèi)存情況局冰,使用printf “%x\n” <threadid> 可將線程ID轉(zhuǎn)成16進(jìn)制(即上面的nid);

Windows環(huán)境下灌危,沒有自帶命令康二,可以使用Process Explorer工具查看;

CPU占用率不高勇蝙,但響應(yīng)很慢

在整個(gè)請求的過程中多次執(zhí)行Thread Dump然后進(jìn)行對比沫勿,取得?BLOCKED?狀態(tài)的線程列表,通常是因?yàn)榫€程停在了I/O味混、數(shù)據(jù)庫連接或網(wǎng)絡(luò)連接的地方产雹。

在線分析

http://gceasy.io/

使用jca工具分析


工具界面
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市翁锡,隨后出現(xiàn)的幾起案子蔓挖,更是在濱河造成了極大的恐慌,老刑警劉巖馆衔,帶你破解...
    沈念sama閱讀 221,695評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件瘟判,死亡現(xiàn)場離奇詭異,居然都是意外死亡角溃,警方通過查閱死者的電腦和手機(jī)荒适,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,569評論 3 399
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來开镣,“玉大人刀诬,你說我怎么就攤上這事。” “怎么了陕壹?”我有些...
    開封第一講書人閱讀 168,130評論 0 360
  • 文/不壞的土叔 我叫張陵质欲,是天一觀的道長。 經(jīng)常有香客問我糠馆,道長嘶伟,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 59,648評論 1 297
  • 正文 為了忘掉前任又碌,我火速辦了婚禮九昧,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘毕匀。我一直安慰自己铸鹰,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,655評論 6 397
  • 文/花漫 我一把揭開白布皂岔。 她就那樣靜靜地躺著蹋笼,像睡著了一般。 火紅的嫁衣襯著肌膚如雪躁垛。 梳的紋絲不亂的頭發(fā)上剖毯,一...
    開封第一講書人閱讀 52,268評論 1 309
  • 那天,我揣著相機(jī)與錄音教馆,去河邊找鬼逊谋。 笑死,一個(gè)胖子當(dāng)著我的面吹牛土铺,可吹牛的內(nèi)容都是我干的涣狗。 我是一名探鬼主播,決...
    沈念sama閱讀 40,835評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼舒憾,長吁一口氣:“原來是場噩夢啊……” “哼镀钓!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起镀迂,我...
    開封第一講書人閱讀 39,740評論 0 276
  • 序言:老撾萬榮一對情侶失蹤丁溅,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后探遵,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體窟赏,經(jīng)...
    沈念sama閱讀 46,286評論 1 318
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,375評論 3 340
  • 正文 我和宋清朗相戀三年箱季,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了涯穷。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,505評論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡藏雏,死狀恐怖拷况,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤赚瘦,帶...
    沈念sama閱讀 36,185評論 5 350
  • 正文 年R本政府宣布粟誓,位于F島的核電站,受9級特大地震影響起意,放射性物質(zhì)發(fā)生泄漏鹰服。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,873評論 3 333
  • 文/蒙蒙 一揽咕、第九天 我趴在偏房一處隱蔽的房頂上張望悲酷。 院中可真熱鬧,春花似錦亲善、人聲如沸设易。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,357評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至嚎于,卻和暖如春掘而,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背于购。 一陣腳步聲響...
    開封第一講書人閱讀 33,466評論 1 272
  • 我被黑心中介騙來泰國打工袍睡, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人肋僧。 一個(gè)月前我還...
    沈念sama閱讀 48,921評論 3 376
  • 正文 我出身青樓斑胜,卻偏偏與公主長得像,于是被迫代替她去往敵國和親嫌吠。 傳聞我的和親對象是個(gè)殘疾皇子止潘,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,515評論 2 359

推薦閱讀更多精彩內(nèi)容