更新時間:2021-12-06 09:43:08 來源:動力節點 瀏覽975次
Jstack是Jdk自帶的線程跟蹤工具,用于打印指定Java進程的線程堆棧信息。
jstack -l [pid]
注意:windows環境只支持這么一個參數
jstack -l 5524 > c:\users\Administrator\Desktop\jstack.txt
2018-09-14 12:59:46
Full thread dump Java HotSpot(TM) 64-Bit Server VM (25.77-b03 mixed mode):
"ActiveMQ InactivityMonitor Worker" #528 daemon prio=5 os_prio=0 tid=0x000000001ce03800 nid=0x1bc8 waiting on condition [0x000000003dadf000]
java.lang.Thread.State: TIMED_WAITING (parking)
at sun.misc.Unsafe.park(Native Method)
- parking to wait for <0x000000071cf5ea58> (a java.util.concurrent.SynchronousQueue$TransferStack)
at java.util.concurrent.locks.LockSupport.parkNanos(LockSupport.java:215)
at java.util.concurrent.SynchronousQueue$TransferStack.awaitFulfill(SynchronousQueue.java:460)
at java.util.concurrent.SynchronousQueue$TransferStack.transfer(SynchronousQueue.java:362)
at java.util.concurrent.SynchronousQueue.poll(SynchronousQueue.java:941)
at java.util.concurrent.ThreadPoolExecutor.getTask(ThreadPoolExecutor.java:1066)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1127)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at java.lang.Thread.run(Thread.java:745)
Locked ownable synchronizers:
- None
"ActiveMQ InactivityMonitor Worker" #527 daemon prio=5 os_prio=0 tid=0x000000001ce05800 nid=0x22c8 waiting on condition [0x000000003f56e000]
java.lang.Thread.State: TIMED_WAITING (parking)
at sun.misc.Unsafe.park(Native Method)
- parking to wait for <0x000000071cf5ea58> (a java.util.concurrent.SynchronousQueue$TransferStack)
at java.util.concurrent.locks.LockSupport.parkNanos(LockSupport.java:215)
at java.util.concurrent.SynchronousQueue$TransferStack.awaitFulfill(SynchronousQueue.java:460)
at java.util.concurrent.SynchronousQueue$TransferStack.transfer(SynchronousQueue.java:362)
at java.util.concurrent.SynchronousQueue.poll(SynchronousQueue.java:941)
at java.util.concurrent.ThreadPoolExecutor.getTask(ThreadPoolExecutor.java:1066)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1127)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at java.lang.Thread.run(Thread.java:745)
Locked ownable synchronizers:
- None
.........
線程狀態
想要通過jstack命令來分析線程的情況的話,首先要知道線程都有哪些狀態,下面這些狀態是我們使用jstack命令查看線程堆棧信息時可能會看到的線程的幾種狀態:
NEW:未啟動的。不會出現在Dump中。
RUNNABLE:在虛擬機內執行的。運行中狀態,可能里面還能看到locked字樣,表明它獲得了某把鎖。
BLOCKED:受阻塞并等待監視器鎖。被某個鎖(synchronizers)給block住了。
WATING:無限期等待另一個線程執行特定操作。等待某個condition或monitor發生,一般停留在park(), wait(), sleep(),join() 等語句里。
TIMED_WATING:有時限的等待另一個線程的特定操作。和WAITING的區別是wait() 等語句加上了時間限制 wait(timeout)。
TERMINATED:已退出的。
Monitor
在多線程的 JAVA程序中,實現線程之間的同步,就要說說 Monitor。 Monitor是 Java中用以實現線程之間的互斥與協作的主要手段,它可以看成是對象或者 Class的鎖。每一個對象都有,也僅有一個 monitor。下 面這個圖,描述了線程和 Monitor之間關系,以 及線程的狀態轉換圖:
進入區(Entrt Set):表示線程通過synchronized要求獲取對象的鎖。如果對象未被鎖住,則迚入擁有者;否則則在進入區等待。一旦對象鎖被其他線程釋放,立即參與競爭。
擁有者(The Owner):表示某一線程成功競爭到對象鎖。
等待區(Wait Set) :表示線程通過對象的wait方法,釋放對象的鎖,并在等待區等待被喚醒。
從圖中可以看出,一個 Monitor在某個時刻,只能被一個線程擁有,該線程就是 “Active Thread”,而其它線程都是 “Waiting Thread”,分別在兩個隊列 “ Entry Set”和 “Wait Set”里面等候。在 “Entry Set”中等待的線程狀態是 “Waiting for monitor entry”,而在“Wait Set”中等待的線程狀態是 “in Object.wait()”。 先看 “Entry Set”里面的線程。我們稱被 synchronized保護起來的代碼段為臨界區。當一個線程申請進入臨界區時,它就進入了 “Entry Set”隊列。對應的 code就像:
synchronized(obj) {
.........
}
調用修飾
表示線程在方法調用時,額外的重要的操作。線程Dump分析的重要信息。修飾上方的方法調用。
locked <地址> 目標:使用synchronized申請對象鎖成功,監視器的擁有者。
waiting to lock <地址> 目標:使用synchronized申請對象鎖未成功,在迚入區等待。
waiting on <地址> 目標:使用synchronized申請對象鎖成功后,釋放鎖幵在等待區等待。
parking to wait for <地址> 目標 :需與堆棧中的"parking to wait for (atjava.util.concurrent.SynchronousQueue$TransferStack)"結合來看。first–>此線程是在等待某個條件的發生,來把自己喚醒,second–>SynchronousQueue不是一個隊列,其是線程之間移交信息的機制,當我們把一個元素放入到 SynchronousQueue 中時必須有另一個線程正在等待接受移交的任務,因此這就是本線程在等待的條件。
locked
at oracle.jdbc.driver.PhysicalConnection.prepareStatement
- locked <0x00002aab63bf7f58> (a oracle.jdbc.driver.T4CConnection)
at oracle.jdbc.driver.PhysicalConnection.prepareStatement
- locked <0x00002aab63bf7f58> (a oracle.jdbc.driver.T4CConnection)
at com.jiuqi.dna.core.internal.db.datasource.PooledConnection.prepareStatement
通過synchronized關鍵字,成功獲取到了對象的鎖,成為監視器的擁有者,在臨界區內操作。對象鎖是可以線程重入的。
waiting to lock
at com.jiuqi.dna.core.impl.CacheHolder.isVisibleIn(CacheHolder.java:165)
- waiting to lock <0x0000000097ba9aa8> (a CacheHolder)
at com.jiuqi.dna.core.impl.CacheGroup$Index.findHolder
at com.jiuqi.dna.core.impl.ContextImpl.find
at com.jiuqi.dna.bap.basedata.common.util.BaseDataCenter.findInfo
通過synchronized關鍵字,沒有獲取到了對象的鎖,線程在監視器的進入區等待。在調用棧頂出現,線程狀態為Blocked。
waiting on
at java.lang.Object.wait(Native Method)
- waiting on <0x00000000da2defb0> (a WorkingThread)
at com.jiuqi.dna.core.impl.WorkingManager.getWorkToDo
- locked <0x00000000da2defb0> (a WorkingThread)
at com.jiuqi.dna.core.impl.WorkingThread.run
通過synchronized關鍵字,成功獲取到了對象的鎖后,調用了wait方法,進入對象的等待區等待。在調用棧頂出現,線程狀態為WAITING或TIMED_WATING。
parking to wait for
park是基本的線程阻塞原語,不通過監視器在對象上阻塞。隨concurrent包會出現的新的機制,不synchronized體系不同。
runnable:狀態一般為RUNNABLE。
in Object.wait():等待區等待,狀態為WAITING或TIMED_WAITING。
waiting for monitor entry:進入區等待,狀態為BLOCKED。
waiting on condition:等待區等待、被park。
sleeping:休眠的線程,調用了Thread.sleep()。
線程動作
線程狀態產生的原因
Wait on condition 該狀態出現在線程等待某個條件的發生。具體是什么原因,可以結合 stacktrace來分析。 最常見的情況就是線程處于sleep狀態,等待被喚醒。 常見的情況還有等待網絡IO:在java引入nio之前,對于每個網絡連接,都有一個對應的線程來處理網絡的讀寫操作,即使沒有可讀寫的數據,線程仍然阻塞在讀寫操作上,這樣有可能造成資源浪費,而且給操作系統的線程調度也帶來壓力。在 NewIO里采用了新的機制,編寫的服務器程序的性能和可擴展性都得到提高。 正等待網絡讀寫,這可能是一個網絡瓶頸的征兆。因為網絡阻塞導致線程無法執行。一種情況是網絡非常忙,幾 乎消耗了所有的帶寬,仍然有大量數據等待網絡讀 寫;另一種情況也可能是網絡空閑,但由于路由等問題,導致包無法正常的到達。所以要結合系統的一些性能觀察工具來綜合分析,比如 netstat統計單位時間的發送包的數目,如果很明顯超過了所在網絡帶寬的限制 ; 觀察 cpu的利用率,如果系統態的 CPU時間,相對于用戶態的 CPU時間比例較高;如果程序運行在 Solaris 10平臺上,可以用 dtrace工具看系統調用的情況,如果觀察到 read/write的系統調用的次數或者運行時間遙遙領先;這些都指向由于網絡帶寬所限導致的網絡瓶頸。(來自http://www.blogjava.net/jzone/articles/303979.html)
使用windows工具ProcessExplorer來獲取對應的線程信息
windows下揪出java程序占用cpu很高的線程 并找到問題代碼 死循環線程代碼
這個由于不想安裝Linux虛擬機整環境了,請需要的同學直接異步下面鏈接
JVM調優之jstack找出最耗cpu的線程并定位代碼
以上就是關于“Java性能調優工具:Jstack”的介紹,如果大家想了解更多相關知識,可以關注一下動力節點的Java開發工具,里面有更多的介紹在等著大家去了解,希望對大家能夠有所幫助。
0基礎 0學費 15天面授
有基礎 直達就業
業余時間 高薪轉行
工作1~3年,加薪神器
工作3~5年,晉升架構
提交申請后,顧問老師會電話與您溝通安排學習