成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

怎樣分析 JAVA 的 Thread Dumps

cfanr / 3082人閱讀

摘要:線程競爭會引起各種不同的問題,為了分析這些這些問題,你需要使用,能給你提供每個線程的精確狀態(tài)信息。使用怎樣解決問題示例當(dāng)利用率高的異常提取獲取最高使用率的線程。當(dāng)與的連接保持在不正常的狀態(tài),線程將等待直到超時。

  

注: 該文章的原文是由 Tae Jin Gu 編寫,原文地址為 How to Analyze Java Thread Dumps

當(dāng)有障礙,或者是一個基于 JAVA 的 WEB 應(yīng)用運(yùn)行的比預(yù)期慢的時候,我們需要使用 thread dumps。如果對于你來說, thread dumps 是非常復(fù)雜的,這篇文章或許能對你有所幫助。在這里我將解釋在 JAVA 中什么是 threads,他們的類型,怎么被創(chuàng)建的,怎樣管理它們,你怎樣從正在運(yùn)行的應(yīng)用中 dump threads,最后你可以怎樣分析它以及確定瓶頸或者是阻塞線程。本文來自于 JAVA 應(yīng)用程序長期調(diào)試經(jīng)驗(yàn)的結(jié)果。

Java and Thread

一個 web 服務(wù)器使用幾十到幾百個線程來處理大量并發(fā)用戶,如果一個或多個線程使用相同的資源,線程之間的競爭就不可避免了,并且有時候可能會發(fā)生死鎖。

Thread contention 是一個線程等待鎖的一個狀態(tài),這個鎖被另外一個線程持有,等待被釋放,不同的線程頻繁訪問 WEB 應(yīng)用的共享資源。例如,記錄一條日志,線程嘗試記錄日志之前必須先獲取鎖來訪問共享資源。

死鎖是線程競爭的一個特殊狀態(tài),一個或是多個線程在等待其他線程完成它們的任務(wù)為了完成它們自己的任務(wù)。

線程競爭會引起各種不同的問題,為了分析這些這些問題,你需要使用 dump threads,dump threads 能給你提供每個線程的精確狀態(tài)信息。

JAVA 線程的背景資料 線程同步

一個線程可以與其他線程在同一時間內(nèi)被處理。為了確保一致性,當(dāng)多個線程試圖使用共享資源的時候,通過使用 hread synchronization 在同一時間內(nèi),應(yīng)該只有一個線程能訪問共享資源

JAVA 中的線程同步可以使用監(jiān)視器,每個 JAVA 對象都有一個多帶帶的監(jiān)視器,這個監(jiān)視器僅僅只能被一個線程擁有,對于擁有一個由不同的線程所擁有的監(jiān)視器的線程,確實(shí)需要在隊(duì)列中等待,以便其他線程釋放它的監(jiān)視器。

線程狀態(tài)

為了分析一個 thread dump 文件,你需要知道線程狀態(tài)。線程情況在 java.lang.Thread.State 中闡明了。

圖1:線程狀態(tài)

NEW:線程剛被創(chuàng)建,但是還沒有被處理。

RUNNABLE:線程占用了 CPU 并且處理了一個任務(wù)。(或是是在等待狀態(tài)由于操作系統(tǒng)的資源分配)

BLOCKED:該線程正在等待另外的不同的線程釋放鎖,以便獲取監(jiān)視器鎖

WAITING:該線程正在等待,通過使用了 wait, join 或者是 park 方法

TIMED_WAITING:該線程正在等待,通過使用了 sleep, wait, join 或者是 park 方法。(這個與 WAITING 不同是通過方法參數(shù)指定了最大等待時間,WAITING 可以通過時間或者是外部的變化解除)

線程類型

JAVA 的線程類型分為以下兩種:

daemon threads;

非 daemon threads。

Daemon threads 將停止工作當(dāng)沒有其他任何非 Daemon threads 時。即使你不創(chuàng)建任何線程,JAVA 應(yīng)用也將默認(rèn)創(chuàng)建幾個線程。他們大部分是 daemon threads。主要用于任務(wù)處理比如內(nèi)存回收或者是 JMX。

一個運(yùn)行 static void main(String[] args) 方法的線程被作為非 daemon threads 線程創(chuàng)建,并且當(dāng)該線程停止工作的時候,所有任何其他 daemon threads 也將停止工作。(這個運(yùn)行在 main 方法中的線程被稱為 VM thread in HotSpot VM

獲取一個 Thread Dump

我們將介紹三種最常用的方法,記住,有非常多的其他方法可以獲取thread dump,一個 thread dump 僅僅只能在測量的時候顯示線程狀態(tài)。因此為了看得線程狀態(tài)的變化,建議每隔5秒提取5到10次的記錄。

使用 jstack 獲取 Thread Dump

在 JDK1.6 或者是更高的版本中,通過使用 jstack, 在 MS Windows 平臺上可能可以獲取到 Thread Dump。

通過使用 jps 檢查當(dāng)前正在運(yùn)行的JAVA進(jìn)程的 PID。

[user@linux ~]$ jps -v
25780 RemoteTestRunner -Dfile.encoding=UTF-8
25590 sub.rmi.registry.RegistryImpl 2999 -Dapplication.home=/home1/user/java/jdk.1.6.0_24 -Xms8m
26300 sun.tools.jps.Jps -mlvV -Dapplication.home=/home1/user/java/jdk.1.6.0_24 -Xms8m

使用明確的 PID 作為 jstack 的參數(shù)來獲取 thread dumps

[user@linux ~]$ jstack -f 5824
使用 jVisualVM 生成 Thread Dump

通過使用一個程序 jVisualVM 來生成 Thread Dump。

如上圖在左側(cè)的任務(wù)表示當(dāng)前正在運(yùn)行的進(jìn)程列表,點(diǎn)擊你想要信息的那個線程,然后選擇 thread tab 頁來檢查實(shí)時的線程信息。點(diǎn)擊右邊的 Thread Dump 按鈕來獲取 thread dump 文件。

在 Linux 控制臺生成

通過使用 ps -ef 命令來獲取當(dāng)前正在運(yùn)行的 JAVA 應(yīng)用程序的進(jìn)程 ID。

[user@linux ~]$ ps - ef | grep java
user      2477          1    0 Dec23 ?         00:10:45 ...
user    25780 25361   0 15:02 pts/3    00:00:02 ./jstatd -J -Djava.security.policy=jstatd.all.policy -p 2999
user    26335 25361   0 15:49 pts/3    00:00:00 grep java

使用精確的 pid 作為 kill –SIGQUIT(3) 的參數(shù)來獲取 thread dump。

Thread Dump 文件的 線程信息
"pool-1-thread-13" prio=6 tid=0x000000000729a000 nid=0x2fb4 runnable [0x0000000007f0f000] java.lang.Thread.State: RUNNABLE
              at java.net.SocketInputStream.socketRead0(Native Method)

              at java.net.SocketInputStream.read(SocketInputStream.java:129)

              at sun.nio.cs.StreamDecoder.readBytes(StreamDecoder.java:264)

              at sun.nio.cs.StreamDecoder.implRead(StreamDecoder.java:306)

              at sun.nio.cs.StreamDecoder.read(StreamDecoder.java:158)

              - locked <0x0000000780b7e688> (a java.io.InputStreamReader)

              at java.io.InputStreamReader.read(InputStreamReader.java:167)

              at java.io.BufferedReader.fill(BufferedReader.java:136)

              at java.io.BufferedReader.readLine(BufferedReader.java:299)

              - locked <0x0000000780b7e688> (a java.io.InputStreamReader)

              at java.io.BufferedReader.readLine(BufferedReader.java:362)

線程名字:當(dāng)使用 Java.lang.Thread 類生成一個線程的時候,該線程將被命名為 Thread-(Number)。但是當(dāng)使用 java.util.concurrent.ThreadFactory 類的時候,它將被命名為 pool-(number)-thread-(number)。

優(yōu)先級:代表該線程的優(yōu)先級

線程 ID:代表該線程的唯一 ID,(一些有用的信息,比如該線程的 CPU 使用率或者是內(nèi)存使用率,都能通過該線程 ID 獲取到)。

線程狀態(tài):代表該線程當(dāng)前的狀態(tài)

線程調(diào)用棧:代表該線程的調(diào)用棧信息

Thread Dump Patterns by Type When Unable to Obtain a Lock (BLOCKED)

這個應(yīng)用程序的整體性能下降是因?yàn)橐粋€線程占用了鎖阻止了其他線程獲得鎖,在下面的示例中,BLOCKED_TEST pool-1-thread-1 線程占用了 <0x0000000780a000b0> 鎖,然而 BLOCKED_TEST pool-1-thread-2BLOCKED_TEST pool-1-thread-3 threads 正在等待獲取鎖。

 "BLOCKED_TEST pool-1-thread-1" prio=6 tid=0x0000000006904800 nid=0x28f4 runnable [0x000000000785f000]
   java.lang.Thread.State: RUNNABLE
                at java.io.FileOutputStream.writeBytes(Native Method)
                at java.io.FileOutputStream.write(FileOutputStream.java:282)
                at java.io.BufferedOutputStream.flushBuffer(BufferedOutputStream.java:65)
                at java.io.BufferedOutputStream.flush(BufferedOutputStream.java:123)
                - locked <0x0000000780a31778> (a java.io.BufferedOutputStream)
                at java.io.PrintStream.write(PrintStream.java:432)
                - locked <0x0000000780a04118> (a java.io.PrintStream)
                at sun.nio.cs.StreamEncoder.writeBytes(StreamEncoder.java:202)
                at sun.nio.cs.StreamEncoder.implFlushBuffer(StreamEncoder.java:272)
                at sun.nio.cs.StreamEncoder.flushBuffer(StreamEncoder.java:85)
                - locked <0x0000000780a040c0> (a java.io.OutputStreamWriter)
                at java.io.OutputStreamWriter.flushBuffer(OutputStreamWriter.java:168)
                at java.io.PrintStream.newLine(PrintStream.java:496)
                - locked <0x0000000780a04118> (a java.io.PrintStream)
                at java.io.PrintStream.println(PrintStream.java:687)
                - locked <0x0000000780a04118> (a java.io.PrintStream)
                at com.nbp.theplatform.threaddump.ThreadBlockedState.monitorLock(ThreadBlockedState.java:44)
                - locked <0x0000000780a000b0> (a com.nbp.theplatform.threaddump.ThreadBlockedState)
                at com.nbp.theplatform.threaddump.ThreadBlockedState$1.run(ThreadBlockedState.java:7)
                at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886)
                at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908)
                at java.lang.Thread.run(Thread.java:662)

   Locked ownable synchronizers:
                - <0x0000000780a31758> (a java.util.concurrent.locks.ReentrantLock$NonfairSync)

"BLOCKED_TEST pool-1-thread-2" prio=6 tid=0x0000000007673800 nid=0x260c waiting for monitor entry [0x0000000008abf000]
   java.lang.Thread.State: BLOCKED (on object monitor)
                at com.nbp.theplatform.threaddump.ThreadBlockedState.monitorLock(ThreadBlockedState.java:43)
                - waiting to lock <0x0000000780a000b0> (a com.nbp.theplatform.threaddump.ThreadBlockedState)
                at com.nbp.theplatform.threaddump.ThreadBlockedState$2.run(ThreadBlockedState.java:26)
                at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886)
                at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908)
                at java.lang.Thread.run(Thread.java:662)

   Locked ownable synchronizers:
                - <0x0000000780b0c6a0> (a java.util.concurrent.locks.ReentrantLock$NonfairSync)

"BLOCKED_TEST pool-1-thread-3" prio=6 tid=0x00000000074f5800 nid=0x1994 waiting for monitor entry [0x0000000008bbf000]
   java.lang.Thread.State: BLOCKED (on object monitor)
                at com.nbp.theplatform.threaddump.ThreadBlockedState.monitorLock(ThreadBlockedState.java:42)
                - waiting to lock <0x0000000780a000b0> (a com.nbp.theplatform.threaddump.ThreadBlockedState)
                at com.nbp.theplatform.threaddump.ThreadBlockedState$3.run(ThreadBlockedState.java:34)
                at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886
                at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908)
                at java.lang.Thread.run(Thread.java:662)

   Locked ownable synchronizers:
                - <0x0000000780b0e1b8> (a java.util.concurrent.locks.ReentrantLock$NonfairSync)

當(dāng)在死鎖狀態(tài)

這是當(dāng)線程 A 需要獲取線程 B 的鎖來繼續(xù)它的任務(wù),然而線程 B 也需要獲取線程 A 的鎖來繼續(xù)它的任務(wù)的時候發(fā)生的。在 thread dump 中,你能看到 DEADLOCK_TEST-1 線程持有 0x00000007d58f5e48 鎖,并且嘗試獲取 0x00000007d58f5e60 鎖。你也能看到 DEADLOCK_TEST-2 線程持有 0x00000007d58f5e60,并且嘗試獲取 0x00000007d58f5e78,同時 DEADLOCK_TEST-3 線程持有 0x00000007d58f5e78,并且在嘗試獲取 0x00000007d58f5e48 鎖,如你所見,每個線程都在等待獲取另外一個線程的鎖,這狀態(tài)將不會被改變直到一個線程丟棄了它的鎖。

"DEADLOCK_TEST-1" daemon prio=6 tid=0x000000000690f800 nid=0x1820 waiting for monitor entry [0x000000000805f000]
   java.lang.Thread.State: BLOCKED (on object monitor)
                at com.nbp.theplatform.threaddump.ThreadDeadLockState$DeadlockThread.goMonitorDeadlock(ThreadDeadLockState.java:197)
                - waiting to lock <0x00000007d58f5e60> (a com.nbp.theplatform.threaddump.ThreadDeadLockState$Monitor)
                at com.nbp.theplatform.threaddump.ThreadDeadLockState$DeadlockThread.monitorOurLock(ThreadDeadLockState.java:182)
                - locked <0x00000007d58f5e48> (a com.nbp.theplatform.threaddump.ThreadDeadLockState$Monitor)
                at com.nbp.theplatform.threaddump.ThreadDeadLockState$DeadlockThread.run(ThreadDeadLockState.java:135)

   Locked ownable synchronizers:
                - None

"DEADLOCK_TEST-2" daemon prio=6 tid=0x0000000006858800 nid=0x17b8 waiting for monitor entry [0x000000000815f000]
   java.lang.Thread.State: BLOCKED (on object monitor)
                at com.nbp.theplatform.threaddump.ThreadDeadLockState$DeadlockThread.goMonitorDeadlock(ThreadDeadLockState.java:197)
                - waiting to lock <0x00000007d58f5e78> (a com.nbp.theplatform.threaddump.ThreadDeadLockState$Monitor)
                at com.nbp.theplatform.threaddump.ThreadDeadLockState$DeadlockThread.monitorOurLock(ThreadDeadLockState.java:182)
                - locked <0x00000007d58f5e60> (a com.nbp.theplatform.threaddump.ThreadDeadLockState$Monitor)
                at com.nbp.theplatform.threaddump.ThreadDeadLockState$DeadlockThread.run(ThreadDeadLockState.java:135)

   Locked ownable synchronizers:
                - None

"DEADLOCK_TEST-3" daemon prio=6 tid=0x0000000006859000 nid=0x25dc waiting for monitor entry [0x000000000825f000]
   java.lang.Thread.State: BLOCKED (on object monitor)
                at com.nbp.theplatform.threaddump.ThreadDeadLockState$DeadlockThread.goMonitorDeadlock(ThreadDeadLockState.java:197)
                - waiting to lock <0x00000007d58f5e48> (a com.nbp.theplatform.threaddump.ThreadDeadLockState$Monitor)
                at com.nbp.theplatform.threaddump.ThreadDeadLockState$DeadlockThread.monitorOurLock(ThreadDeadLockState.java:182)
                - locked <0x00000007d58f5e78> (a com.nbp.theplatform.threaddump.ThreadDeadLockState$Monitor)
                at com.nbp.theplatform.threaddump.ThreadDeadLockState$DeadlockThread.run(ThreadDeadLockState.java:135)

   Locked ownable synchronizers:
                - None
當(dāng)持續(xù)等待從遠(yuǎn)處服務(wù)器接收消息

該線程是正常的,因?yàn)樗臓顟B(tài)為 RUNNABLE,盡管如此,當(dāng)你按照時間順序排列 Thread Dump,你會發(fā)現(xiàn) socketReadThread 線程正在無限等待讀取 socket。

"socketReadThread" prio=6 tid=0x0000000006a0d800 nid=0x1b40 runnable [0x00000000089ef000]
   java.lang.Thread.State: RUNNABLE
                at java.net.SocketInputStream.socketRead0(Native Method)
                at java.net.SocketInputStream.read(SocketInputStream.java:129)
                at sun.nio.cs.StreamDecoder.readBytes(StreamDecoder.java:264)
                at sun.nio.cs.StreamDecoder.implRead(StreamDecoder.java:306)
                at sun.nio.cs.StreamDecoder.read(StreamDecoder.java:158)
                - locked <0x00000007d78a2230> (a java.io.InputStreamReader)
                at sun.nio.cs.StreamDecoder.read0(StreamDecoder.java:107)
                - locked <0x00000007d78a2230> (a java.io.InputStreamReader)
                at sun.nio.cs.StreamDecoder.read(StreamDecoder.java:93)
                at java.io.InputStreamReader.read(InputStreamReader.java:151)
                at com.nbp.theplatform.threaddump.ThreadSocketReadState$1.run(ThreadSocketReadState.java:27)
                at java.lang.Thread.run(Thread.java:662)
當(dāng) Waiting 時

線程保持在 Waiting 狀態(tài),在 Thread Dump 中,IoWaitThread 線程保持等待狀態(tài)來從 LinkedBlockingQueue 接收消息。如果 LinkedBlockingQueue 一直沒有消息,該線程的狀態(tài)將不會改變。


"IoWaitThread" prio=6 tid=0x0000000007334800 nid=0x2b3c waiting on condition [0x000000000893f000] java.lang.Thread.State: WAITING (parking) at sun.misc.Unsafe.park(Native Method) - parking to wait for <0x00000007d5c45850> (a java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject) at java.util.concurrent.locks.LockSupport.park(LockSupport.java:156) at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await(AbstractQueuedSynchronizer.java:1987) at java.util.concurrent.LinkedBlockingDeque.takeFirst(LinkedBlockingDeque.java:440) at java.util.concurrent.LinkedBlockingDeque.take(LinkedBlockingDeque.java:629) at com.nbp.theplatform.threaddump.ThreadIoWaitState$IoWaitHandler2.run(ThreadIoWaitState.java:89) at java.lang.Thread.run(Thread.java:662)
當(dāng)線程的資源不能正常的被組織

不必要的線程會堆積起來,當(dāng)線程的資源不能被正常的組織的話,如果這個發(fā)送了,建議監(jiān)控線程組織過程或檢查線程終止的條件。

使用 Thread Dump 怎樣解決問題 示例1:當(dāng) CPU 利用率高的異常

提取獲取最高 CPU 使用率的線程。

[user@linux ~]$ ps -mo pid.lwp.stime.time.cpu -C java

     PID         LWP          STIME                  TIME        %CPU
10029               -         Dec07          00:02:02           99.5
         -       10039        Dec07          00:00:00              0.1
         -       10040        Dec07          00:00:00           95.5

從這個應(yīng)用中,發(fā)現(xiàn)使用 CPU 最高的線程。

獲取使用 CPU 最多的輕量級進(jìn)程(LWP),把它的唯一標(biāo)示碼 (10039) 轉(zhuǎn)換成十六進(jìn)制 (0x2737)。

然后獲取進(jìn)程的 Thread Dump,檢查進(jìn)程的動作。

通過 PID 10029 來提取應(yīng)用程序的 Thread Dump,然后通過一個 nid 0x2737 來找到這個線程。

"NioProcessor-2" prio=10 tid=0x0a8d2800 nid=0x2737 runnable [0x49aa5000]
java.lang.Thread.State: RUNNABLE
                at sun.nio.ch.EPollArrayWrapper.epollWait(Native Method)
                at sun.nio.ch.EPollArrayWrapper.poll(EPollArrayWrapper.java:210)
                at sun.nio.ch.EPollSelectorImpl.doSelect(EPollSelectorImpl.java:65)
                at sun.nio.ch.SelectorImpl.lockAndDoSelect(SelectorImpl.java:69)
                - locked <0x74c52678> (a sun.nio.ch.Util$1)
                - locked <0x74c52668> (a java.util.Collections$UnmodifiableSet)
                - locked <0x74c501b0> (a sun.nio.ch.EPollSelectorImpl)
                at sun.nio.ch.SelectorImpl.select(SelectorImpl.java:80)
                at external.org.apache.mina.transport.socket.nio.NioProcessor.select(NioProcessor.java:65)
                at external.org.apache.mina.common.AbstractPollingIoProcessor$Worker.run(AbstractPollingIoProcessor.java:708)
                at external.org.apache.mina.util.NamePreservingRunnable.run(NamePreservingRunnable.java:51)
                at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886)
                at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908)
                at java.lang.Thread.run(Thread.java:662)

每個小時的幾個時間提取 Thread Dump,然后檢查線程的狀態(tài)來確定問題。

示例2:當(dāng)進(jìn)程的性能異常的慢

多次獲得 thread dumps 后,找出 BLOCKED 狀態(tài)的線程列表。

" DB-Processor-13" daemon prio=5 tid=0x003edf98 nid=0xca waiting for monitor entry [0x000000000825f000]
java.lang.Thread.State: BLOCKED (on object monitor)
                at beans.ConnectionPool.getConnection(ConnectionPool.java:102)
                - waiting to lock <0xe0375410> (a beans.ConnectionPool)
                at beans.cus.ServiceCnt.getTodayCount(ServiceCnt.java:111)
                at beans.cus.ServiceCnt.insertCount(ServiceCnt.java:43)

"DB-Processor-14" daemon prio=5 tid=0x003edf98 nid=0xca waiting for monitor entry [0x000000000825f020]
java.lang.Thread.State: BLOCKED (on object monitor)
                at beans.ConnectionPool.getConnection(ConnectionPool.java:102)
                - waiting to lock <0xe0375410> (a beans.ConnectionPool)
                at beans.cus.ServiceCnt.getTodayCount(ServiceCnt.java:111)
                at beans.cus.ServiceCnt.insertCount(ServiceCnt.java:43)

" DB-Processor-3" daemon prio=5 tid=0x00928248 nid=0x8b waiting for monitor entry [0x000000000825d080]
java.lang.Thread.State: RUNNABLE
                at oracle.jdbc.driver.OracleConnection.isClosed(OracleConnection.java:570)
                - waiting to lock <0xe03ba2e0> (a oracle.jdbc.driver.OracleConnection)
                at beans.ConnectionPool.getConnection(ConnectionPool.java:112)
                - locked <0xe0386580> (a java.util.Vector)
                - locked <0xe0375410> (a beans.ConnectionPool)
                at beans.cus.Cue_1700c.GetNationList(Cue_1700c.java:66)
                at org.apache.jsp.cue_1700c_jsp._jspService(cue_1700c_jsp.java:120)

在多次獲取 thread dumps 后,取得 BLOCKED 狀態(tài)的線程列表。

如果線程是 BLOCKED 的,提取線程嘗試獲取的相關(guān)聯(lián)的鎖。

通過 thread dumps,你能確定線程狀態(tài)停止在 BLOCKED,因?yàn)殒i <0xe0375410> 不能被獲取到,這個問題可以通過分析當(dāng)前夯住的線程的 stack trace 來解決。

使用 DBMS 的時候,為什么以上的范例經(jīng)常出現(xiàn)再應(yīng)用程序中,這有兩個原因。第一個原因是配置不當(dāng)。盡管事實(shí)是該線程仍然在工作,它們不能展示它們最好的性能,因?yàn)?DBCP 的配置文件沒有配置正確。如果你多次提取 thread dumps 并且對比它們,你將經(jīng)常看到被阻塞的線程之前處于不同的狀態(tài)。

第二個原因是不正常的連接。當(dāng)與 DBMS 的連接保持在不正常的狀態(tài),線程將等待直到超時。在這個例子中,通過多次提取 thread dumps 并對比它們,你會發(fā)現(xiàn)與 DBMS 相關(guān)的線程仍然在阻塞狀態(tài)。通過適當(dāng)改變一些值,比如超時時間,你可以縮短問題發(fā)生的時間。

為簡單的 Thread Dump 命名線程編碼

當(dāng)使用 java.lang.Thread 對象創(chuàng)建線程的時候,線程被命名為 Thread-(Number) 。當(dāng)使用 java.util.concurrent.DefaultThreadFactory 對象創(chuàng)建線程的時候,線程被命名為 named pool-(Number)-thread-(Number)。當(dāng)為應(yīng)用程序分析成百上千的線程的時候,如果線程依然用它們默認(rèn)的名字,分析它們將變得非常困難,因?yàn)檫@是非常難以辨別這些線程來分析的。

因此,你被建議開發(fā)一個命名線程的規(guī)則當(dāng)一個新線程被創(chuàng)建的時候。

當(dāng)你使用 java.lang.Thread 創(chuàng)建線程,你可以通過創(chuàng)建參數(shù)給該線程定義個約定俗成的名字。

public Thread(Runnable target, String name);
public Thread(ThreadGroup group, String name);
public Thread(ThreadGroup group, Runnable target, String name);
public Thread(ThreadGroup group, Runnable target, String name, long stackSize);

當(dāng)你使用 java.util.concurrent.ThreadFactory 創(chuàng)建線程的時候,你可以通過生成你自己的線程工廠來命名它,如果你不需要特別的功能性,你可以使用 MyThreadFactory 作為以下描述:

import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.atomic.AtomicInteger;

public class MyThreadFactory implements ThreadFactory {
  private static final ConcurrentHashMap POOL_NUMBER =
                                                       new ConcurrentHashMap();
  private final ThreadGroup group;
  private final AtomicInteger threadNumber = new AtomicInteger(1);
  private final String namePrefix;

  public MyThreadFactory(String threadPoolName) {

      if (threadPoolName == null) {
          throw new NullPointerException("threadPoolName");
      }
            POOL_NUMBER.putIfAbsent(threadPoolName, new AtomicInteger());

      SecurityManager securityManager = System.getSecurityManager();
      group = (securityManager != null) ? securityManager.getThreadGroup() :
                                                    Thread.currentThread().getThreadGroup();

      AtomicInteger poolCount = POOL_NUMBER.get(threadPoolName);

      if (poolCount == null) {
            namePrefix = threadPoolName + " pool-00-thread-";
      } else {
            namePrefix = threadPoolName + " pool-" + poolCount.getAndIncrement() + "-thread-";
      }
  }

  public Thread newThread(Runnable runnable) {
      Thread thread = new Thread(group, runnable, namePrefix + threadNumber.getAndIncrement(), 0);

      if (thread.isDaemon()) {
            thread.setDaemon(false);
      }

      if (thread.getPriority() != Thread.NORM_PRIORITY) {
            thread.setPriority(Thread.NORM_PRIORITY);
      }

      return thread;
  }
}
使用 MBean 獲取更多的細(xì)節(jié)信息

你可以使用 MBean 來獲取 ThreadInfo 對象。你也可以獲取更加多通過 thread dumps 不能獲取的信息。通過使用 ThreadInfo

ThreadMXBean mxBean = ManagementFactory.getThreadMXBean();
long[] threadIds = mxBean.getAllThreadIds();
ThreadInfo[] threadInfos =
                mxBean.getThreadInfo(threadIds);

for (ThreadInfo threadInfo : threadInfos) {
  System.out.println(
      threadInfo.getThreadName());
  System.out.println(
      threadInfo.getBlockedCount());
  System.out.println(
      threadInfo.getBlockedTime());
  System.out.println(
      threadInfo.getWaitedCount());
  System.out.println(
      threadInfo.getWaitedTime());
}

你可以使用方法 ThreadInfo 來提取阻塞線程或者是等待線程花費(fèi)的時間。并利用這一點(diǎn),你也可以得到那些處于非活動狀態(tài)的時間異常長的線程列表。

總結(jié)

在本文中,我關(guān)注的是為開發(fā)人員提供了大量的多線程編程經(jīng)驗(yàn),本素材可能是常識。對于經(jīng)驗(yàn)較少的開發(fā)人員來說,我覺得我直接跳過 thread dumps,不提供足夠的關(guān)于 thread activities 的背景知識。這是由于我的知識缺乏,所以我不能很清晰的簡潔明了的解釋 thread activities。我衷心的希望本文能給很多開發(fā)人員提供幫助。

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/64133.html

相關(guān)文章

  • LeakCanary開源項(xiàng)目

    摘要:前兩天,開源了一個內(nèi)存泄露自動探測神器,它是一個和的內(nèi)存泄露檢測庫,可以大幅度減少了開發(fā)中遇到的問題,對于開發(fā)者來說,無疑是個福音,下面對該庫的進(jìn)行簡單的翻譯小漏不補(bǔ)沉大船。隨著時間過去越來越多熟知的內(nèi)存泄露問題被制造商在開源項(xiàng)目中修復(fù)。 前兩天,Square開源了一個內(nèi)存泄露自動探測神器——LeakCanary,它是一個Android和Java的內(nèi)存泄露檢測庫,可以大幅度減少了開發(fā)中...

    JerryC 評論0 收藏0
  • JAVA 多線程和并發(fā)基礎(chǔ)

    摘要:線程可以被稱為輕量級進(jìn)程。一個守護(hù)線程是在后臺執(zhí)行并且不會阻止終止的線程。其他的線程狀態(tài)還有,和。上下文切換是多任務(wù)操作系統(tǒng)和多線程環(huán)境的基本特征。在的線程中并沒有可供任何對象使用的鎖和同步器。 原文:Java Multi-Threading and Concurrency Interview Questions with Answers 翻譯:并發(fā)編程網(wǎng) - 鄭旭東 校對:方騰飛 多...

    vboy1010 評論0 收藏0
  • Thread類源碼解讀(3)——線程中斷interrupt

    摘要:現(xiàn)在終止一個線程,基本上只能靠曲線救國式的中斷來實(shí)現(xiàn)。中斷機(jī)制的核心在于中斷狀態(tài)和異常中斷狀態(tài)設(shè)置一個中斷狀態(tài)清除一個中斷狀態(tài)方法同時會返回線程原來的中斷的狀態(tài)。中斷異常中斷異常一般是線程被中斷后,在一些類型的方法如中拋出。 前言 系列文章目錄 線程中斷是一個很重要的概念,通常,取消一個任務(wù)的執(zhí)行,最好的,同時也是最合理的方法,就是通過中斷。 本篇我們主要還是通過源碼分析來看看中斷的概...

    fevin 評論0 收藏0

發(fā)表評論

0條評論

最新活動
閱讀需要支付1元查看
<