開門見山,本文將簡述如何使用java thread dump來分析CPU高使用率以及線程死鎖問題。
一般java thread dump用於web開發中分析web容器或是應用服務器的性能問題還是比較常用並有效的。常用的入門級web容器Tomcat,以及高級別的jboss、websphere、weblogic等的性能調優問題都可以使用java thread dump來分析。
首先,闡述一下thread dump常用來解決的是何種問題
(1)高CPU使用
(2)線程死鎖
其次,使用步驟[以JBOSS為例]
1..get thread dump log
(1)找到應用程序所在的進程號,命令如下
ps aux |grep 'jboss' | grep 'java'、
獲取需要的PID
(2)執行sudo kill -3 PID獲取thread dump log(PID是第一步獲取)。
注意:在不同的linux環境下執行輸出的日志的地方可能不同。在IBM的PowerPC小型機上的linux上執行kill -3 pid會在工作目錄下產生類似javacore.20100409.161739.7614.0001.txt的文件。JBOSS默認環境下,thread dump log輸出到jboss console,所以thread dump信息會輸出到個人定義的控制台打印log中。
部分示例如下所以:
引用
2010-10-08 20:27:42
Full thread dump Java HotSpot(TM) Server VM (16.3-b01 mixed mode):
"http-182.50.0.138-8084-6" daemon prio=10 tid=0x08ce5000 nid=0x6a4c in Object.wait() [0x87b5c000]
java.lang.Thread.State: WAITING (on object monitor)
at java.lang.Object.wait(Native Method)
- waiting on <0x95eb81b0> (a org.apache.tomcat.util.net.JIoEndpoint$Worker)
at java.lang.Object.wait(Object.java:485)
at org.apache.tomcat.util.net.JIoEndpoint$Worker.await(JIoEndpoint.java:415)
- locked <0x95eb81b0> (a org.apache.tomcat.util.net.JIoEndpoint$Worker)
at org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:441)
at java.lang.Thread.run(Thread.java:619)
"http-182.50.0.138-8084-5" daemon prio=10 tid=0x08c2e000 nid=0x6a4b in Object.wait() [0x87bad000]
java.lang.Thread.State: WAITING (on object monitor)
at java.lang.Object.wait(Native Method)
- waiting on <0x95ed0600> (a org.apache.tomcat.util.net.JIoEndpoint$Worker)
at java.lang.Object.wait(Object.java:485)
at org.apache.tomcat.util.net.JIoEndpoint$Worker.await(JIoEndpoint.java:415)
- locked <0x95ed0600> (a org.apache.tomcat.util.net.JIoEndpoint$Worker)
at org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:441)
at java.lang.Thread.run(Thread.java:619)
"ajp-127.0.0.1-8009-Acceptor-0" daemon prio=10 tid=0x894de800 nid=0x6a45 runnable [0x881f3000]
java.lang.Thread.State: RUNNABLE
at java.net.PlainSocketImpl.socketAccept(Native Method)
at java.net.PlainSocketImpl.accept(PlainSocketImpl.java:390)
- locked <0x949c1288> (a java.net.SocksSocketImpl)
at java.net.ServerSocket.implAccept(ServerSocket.java:453)
at java.net.ServerSocket.accept(ServerSocket.java:421)
at org.apache.tomcat.util.net.DefaultServerSocketFactory.acceptSocket(DefaultServerSocketFactory.java:61)
at org.apache.tomcat.util.net.JIoEndpoint$Acceptor.run(JIoEndpoint.java:309)
at java.lang.Thread.run(Thread.java:619)
DefaultQuartzScheduler_QuartzSchedulerThread" prio=10 tid=0x8a460800 nid=0x6a38 sleeping[0x88818000]
java.lang.Thread.State: TIMED_WAITING (sleeping)
at java.lang.Thread.sleep(Native Method)
at org.quartz.core.QuartzSchedulerThread.run(QuartzSchedulerThread.java:394)
(3)獲取線程信息
使用上面的ps或者使用top命令也可以。獲取的線程信息如下所示:
引用
27143 root 20 0 780m 376m 11m S 17 11.5 2:56.48 java
4839 root 20 0 778m 162m 11m S 10 5.0 1717:03 java
5049 root 20 0 764m 147m 11m S 4 4.5 1744:06 java
1 root 20 0 2100 720 624 S 0 0.0 0:28.08 init
2 root 15 -5 0 0 0 S 0 0.0 0:00.00 kthreadd
3 root RT -5 0 0 0 S 0 0.0 0:00.44 migration/0
第一列是十進制PID,需要轉化為16進制後才能和thread dump信息對應。
2.分析thread dump信息[不在列舉示例,只講思想]
(1)分析高CPU使用線程的thread dump信息,查找那些代碼導致高CPU使用。
(2)線程死鎖
a.為了發現線程動態變化,需要多次做thread dump,每次間隔10-30s為佳.
b.線程狀態用 runnable(正在運行)、waiting for monitor(主動等待)、waiting for monitor entry(死鎖)。所以我們最多的是關注runnable和entry類型的線程。
一種典型的死鎖是在server端多個應用同時使用同一個jboss資源,這時候需要將多個應用分不到不用的隊列中