前言
線程dump是非常有用的診斷java應(yīng)用問題的工具臼寄,每一個(gè)java虛擬機(jī)都有及時(shí)生成顯示所有線程在某一點(diǎn)狀態(tài)的線程dump的能力。雖然各個(gè)java虛擬機(jī)線程dump打印輸出格式上略微有一些不同溜宽,但是線程dump出來的信息包含線程基本信息吉拳;線程的運(yùn)行狀態(tài)、標(biāo)識(shí)和調(diào)用的堆棧适揉;調(diào)用的堆棧包含完整的類名留攒,所執(zhí)行的方法煤惩,如果可能的話還有源代碼的行數(shù)。
JVM中的許多問題都可以使用線程dump文件來進(jìn)行診斷炼邀,其中比較典型的包括線程阻塞魄揉,CPU使用率過高,JVM Crash拭宁,堆內(nèi)存不足和類裝載等問題洛退。
導(dǎo)出
1、查詢java進(jìn)程pid
- 使用jps [-l]命令查看本機(jī)所有java進(jìn)程pid
jps [-l]
2杰标、使用top查看目前正在運(yùn)行的進(jìn)程使用系統(tǒng)資源情況
top
當(dāng)前占用cpu最高26.5%的進(jìn)程為27796的java程序
3兵怯、導(dǎo)出指定進(jìn)程pid所有線程信息
- 使用jstack將所有線程信息導(dǎo)出到指定文件中(jstack了解傳送門)
1)將所有線程信息輸入到指定文件中
jstack [-l] pid > xxx.log
2)-F (當(dāng)'jstack [-l] pid'沒有響應(yīng),強(qiáng)制導(dǎo)出堆棧dump)
jstack -F [-m] [-l] pid >xxx.log
4腔剂、分析
線程狀態(tài)介紹
死鎖摇零,Deadlock(重點(diǎn)關(guān)注) :一般指多個(gè)線程調(diào)用間,進(jìn)入相互資源占用桶蝎,導(dǎo)致一直等待無法釋放的情況驻仅。
執(zhí)行中,Runnable :一般指該線程正在執(zhí)行狀態(tài)中登渣,該線程占用了資源噪服,正在處理某個(gè)請(qǐng)求,有可能正在傳遞SQL到數(shù)據(jù)庫執(zhí)行胜茧,有可能在對(duì)某個(gè)文件操作粘优,有可能進(jìn)行數(shù)據(jù)類型等轉(zhuǎn)換。
等待資源呻顽,Waiting on condition(重點(diǎn)關(guān)注) :等待資源雹顺,或等待某個(gè)條件的發(fā)生。具體原因需結(jié)合 stacktrace來分析廊遍。
??1嬉愧、如果堆棧信息明確是應(yīng)用代碼,則證明該線程正在等待資源喉前。一般是大量讀取某資源没酣,且該資源采用了資源鎖的情況下,線程進(jìn)入等待狀態(tài)卵迂,等待資源的讀取裕便。
又或者,正在等待其他線程的執(zhí)行等见咒。
??2偿衰、如果發(fā)現(xiàn)有大量的線程都在處在 Wait on condition,從線程 stack看,正等待網(wǎng)絡(luò)讀寫下翎,這可能是一個(gè)網(wǎng)絡(luò)瓶頸的征兆囱嫩。因?yàn)榫W(wǎng)絡(luò)阻塞導(dǎo)致線程無法執(zhí)行。
????2.1漏设、一種情況是網(wǎng)絡(luò)非常忙墨闲,幾乎消耗了所有的帶寬,仍然有大量數(shù)據(jù)等待網(wǎng)絡(luò)讀寫郑口;
????2.2鸳碧、另一種情況也可能是網(wǎng)絡(luò)空閑,但由于路由等問題犬性,導(dǎo)致包無法正常的到達(dá)瞻离。
??3、另外一種出現(xiàn) Wait on condition的常見情況是該線程在 sleep乒裆,等待 sleep的時(shí)間到了時(shí)候而涉,將被喚醒娄帖。等待獲取監(jiān)視器,Waiting on monitor entry(重點(diǎn)關(guān)注)
-
對(duì)象等待中,Object.wait() 或 TIMED_WAITING
??Waiting for monitor entry 和 in Object.wait():
??Monitor(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()”
- 暫停互纯,Suspended
- 阻塞瑟幕,Blocked(重點(diǎn)關(guān)注) :是指當(dāng)前線程執(zhí)行過程中,所需要的資源長時(shí)間等待卻一直未能獲取到伟姐,被容器的線程管理器標(biāo)識(shí)為阻塞狀態(tài)收苏,可以理解為等待資源超時(shí)的線程。
- 停止愤兵,Parked
jvm_27796.log展示
stack trace實(shí)例分析
"consumer_redirectUrl_topic_jmq206_1546013217302" daemon prio=10 tid=0x00007f1bf03f6800 nid=0x693e waiting on condition [0x00007f1b38388000]
java.lang.Thread.State: TIMED_WAITING (parking)
at sun.misc.Unsafe.park(Native Method)
- parking to wait for <0x00000000f76e21a0> (a java.util.concurrent.CountDownLatch$Sync)
at java.util.concurrent.locks.LockSupport.parkNanos(LockSupport.java:226)
at java.util.concurrent.locks.AbstractQueuedSynchronizer.doAcquireSharedNanos(AbstractQueuedSynchronizer.java:1033)
at java.util.concurrent.locks.AbstractQueuedSynchronizer.tryAcquireSharedNanos(AbstractQueuedSynchronizer.java:1326)
at java.util.concurrent.CountDownLatch.await(CountDownLatch.java:282)
at com.jd.jmq.common.network.netty.ResponseFuture.await(ResponseFuture.java:133)
at com.jd.jmq.common.network.netty.NettyTransport.sync(NettyTransport.java:241)
at com.jd.jmq.common.network.netty.failover.FailoverNettyClient.sync(FailoverNettyClient.java:94)
at com.jd.jmq.client.consumer.GroupConsumer.pull(GroupConsumer.java:246)
at com.jd.jmq.client.consumer.GroupConsumer$QueueConsumer.run(GroupConsumer.java:445)
at java.lang.Thread.run(Thread.java:745)
Locked ownable synchronizers:
- None
- 線程名:consumer_redirectUrl_topic_jmq206_1546013217302
- 線程優(yōu)先級(jí):prio=10
- java線程的identifier:tid=0x00007f1bf03f6800
- native線程的identifier:nid=0x693e
- 線程的狀態(tài):waiting on condition [0x00007f1b38388000]
java.lang.Thread.State: TIMED_WAITING (parking) - 線程棧起始地址:[0x00007f1b38388000]
找出某進(jìn)程中要分析的線程ID
top -H -p <pid>
將線程ID轉(zhuǎn)換為16進(jìn)制后,在線程dump文件中搜索相關(guān)信息
例如:27840==》6cc0
"System_Clock" daemon prio=10 tid=0x00007f1c2cbc6800 nid=0x6cc0 runnable [0x00007f1c24872000]
java.lang.Thread.State: TIMED_WAITING (parking)
at sun.misc.Unsafe.park(Native Method)
- parking to wait for <0x00000000c0c9d918> (a java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject)
at java.util.concurrent.locks.LockSupport.parkNanos(LockSupport.java:226)
at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.awaitNanos(AbstractQueuedSynchronizer.java:2082)
at java.util.concurrent.ScheduledThreadPoolExecutor$DelayedWorkQueue.take(ScheduledThreadPoolExecutor.java:1090)
at java.util.concurrent.ScheduledThreadPoolExecutor$DelayedWorkQueue.take(ScheduledThreadPoolExecutor.java:807)
at java.util.concurrent.ThreadPoolExecutor.getTask(ThreadPoolExecutor.java:1068)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1130)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
at java.lang.Thread.run(Thread.java:745)
Locked ownable synchronizers:
- None