jstack 脚本 自动日志_深入理解jstack日志
Tags : jstack日志發(fā)表時(shí)間:
2019-03-17 23:53:19
在分析線上問題時(shí)常使用到j(luò)stack 命令將當(dāng)時(shí)Java應(yīng)用程序的線程堆棧dump出來。
面對(duì)jstack 日志,我們?nèi)绾尾榭?#xff1f;
首先要清楚線程的狀態(tài)
線程的狀態(tài)有:new、runnable、running、waiting、timed_waiting、blocked、dead
線程狀態(tài)變遷圖:
各狀態(tài)說明:
New: 當(dāng)線程對(duì)象創(chuàng)建時(shí)存在的狀態(tài),此時(shí)線程不可能執(zhí)行;
Runnable:當(dāng)調(diào)用thread.start()后,線程變成為Runnable狀態(tài)。只要得到CPU,就可以執(zhí)行;
Running:線程正在執(zhí)行;
Waiting:執(zhí)行thread.join()或在鎖對(duì)象調(diào)用obj.wait()等情況就會(huì)進(jìn)該狀態(tài),表明線程正處于等待某個(gè)資源或條件發(fā)生來喚醒自己;
Timed_Waiting:執(zhí)行Thread.sleep(long)、thread.join(long)或obj.wait(long)等就會(huì)進(jìn)該狀態(tài),與Waiting的區(qū)別在于Timed_Waiting的等待有時(shí)間限制;
Blocked:如果進(jìn)入同步方法或同步代碼塊,沒有獲取到鎖,則會(huì)進(jìn)入該狀態(tài);
Dead:線程執(zhí)行完畢,或者拋出了未捕獲的異常之后,會(huì)進(jìn)入dead狀態(tài),表示該線程結(jié)束
其次,對(duì)于jstack日志,我們要著重關(guān)注如下關(guān)鍵信息
Deadlock:表示有死鎖
Waiting on condition:等待某個(gè)資源或條件發(fā)生來喚醒自己。具體需要結(jié)合jstacktrace來分析,比如線程正在sleep,網(wǎng)絡(luò)讀寫繁忙而等待
Blocked:阻塞 Waiting on monitor entry:在等待獲取鎖
in Object.wait():獲取鎖后又執(zhí)行obj.wait()放棄鎖
對(duì)于Waiting on monitor entry 和 in Object.wait()的詳細(xì)描述:Monitor是 Java中用以實(shí)現(xiàn)線程之間的互斥與協(xié)作的主要手段,它可以看成是對(duì)象或者 Class的鎖。每一個(gè)對(duì)象都有,也僅有一個(gè) monitor。從下圖中可以看出,每個(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()"
最后通過示例來實(shí)踐一下
示例一:描述 Blocked 和 Waiting to lock
執(zhí)行后程序輸出:
Thread[main,5,main]
說明主線程先進(jìn)入同步代碼塊,獲取到thread2對(duì)象上的鎖。
通過jstack輸出結(jié)果:
先說明下日志格式:
"thread2"為線程名稱,在平時(shí)創(chuàng)建線程或線程池時(shí)請(qǐng)務(wù)必取一個(gè)見明之義的線程名稱,方便排查問題;
prio=6:線程優(yōu)先級(jí),不用關(guān)心;
tid=0x0000000006540800:線程id,不用關(guān)心;
nid=0x2be4:操作系統(tǒng)映射的線程id, 非常關(guān)鍵,后面再使用jstack時(shí)補(bǔ)充;
waiting for monitor entry:表示線程正在等待獲取鎖
0x0000000006dbf000:線程棧起始地址
從jstack日志中,可以看到:主線程獲取到thread2對(duì)象上的鎖,因此正在執(zhí)行sleep操作,狀態(tài)為TIMED_WAINTING, 而thread2由于未獲取到thread2對(duì)象上的鎖,因此處于BLOCKED狀態(tài)。
再細(xì)看,thread2 正在"waiting to lock <0x00000000d719d280>",即試圖在地址為0x00000000d719d280所在的對(duì)象獲取鎖,而該鎖卻被main線程占有(locked <0x00000000d719d280>)。main線程正在"waiting on condition",說明正在等待某個(gè)條件觸發(fā),由jstacktrace來看,此線程正在sleep。
經(jīng)驗(yàn):如果在jstack日志發(fā)現(xiàn)大量的線程在waiting to lock 某個(gè)地址,只要能查到哪個(gè)線程獲取到鎖就可以方便定位問題了
示例二:描述waiting on condition
]
jstack日志輸出結(jié)果:
從日志中可以看到,main線程的狀態(tài)是Waiting,正在"waiting on condition"來喚醒自己。
結(jié)合jstackstrace日志來看,"parking to wait for <0x00000000d719ba70> (a java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject)"說明在調(diào)用ArrayBlockingQueue.put()阻塞了。
示例三:描述Object.wait()
程序輸出結(jié)果:
Thread[thread2,5,main]
Thread[main,5,main]
說明線程thread2先進(jìn)入同步代碼塊,獲取到thread2對(duì)象上的鎖。
jstack日志輸出結(jié)果:
可以看出:線程thread2的狀態(tài)是"Waiting", 正在"in Object.wait()"。表明該線程在獲取到對(duì)象鎖后,調(diào)用obj.wait()方法,放棄了鎖,進(jìn)入了"Wait Set"隊(duì)列。
...閱讀原文
總結(jié)
以上是生活随笔為你收集整理的jstack 脚本 自动日志_深入理解jstack日志的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: php sslv3握手失败,Boost
- 下一篇: qnetworkreply 获取状态_谈