摘要:線程競爭會引起各種不同的問題,為了分析這些這些問題,你需要使用,能給你提供每個線程的精確狀態信息。使用怎樣解決問題示例當利用率高的異常提取獲取最高使用率的線程。當與的連接保持在不正常的狀態,線程將等待直到超時。
注: 該文章的原文是由 Tae Jin Gu 編寫,原文地址為 How to Analyze Java Thread Dumps
當有障礙,或者是一個基于 JAVA 的 WEB 應用運行的比預期慢的時候,我們需要使用 thread dumps。如果對于你來說, thread dumps 是非常復雜的,這篇文章或許能對你有所幫助。在這里我將解釋在 JAVA 中什么是 threads,他們的類型,怎么被創建的,怎樣管理它們,你怎樣從正在運行的應用中 dump threads,最后你可以怎樣分析它以及確定瓶頸或者是阻塞線程。本文來自于 JAVA 應用程序長期調試經驗的結果。
Java and Thread一個 web 服務器使用幾十到幾百個線程來處理大量并發用戶,如果一個或多個線程使用相同的資源,線程之間的競爭就不可避免了,并且有時候可能會發生死鎖。
Thread contention 是一個線程等待鎖的一個狀態,這個鎖被另外一個線程持有,等待被釋放,不同的線程頻繁訪問 WEB 應用的共享資源。例如,記錄一條日志,線程嘗試記錄日志之前必須先獲取鎖來訪問共享資源。
死鎖是線程競爭的一個特殊狀態,一個或是多個線程在等待其他線程完成它們的任務為了完成它們自己的任務。
線程競爭會引起各種不同的問題,為了分析這些這些問題,你需要使用 dump threads,dump threads 能給你提供每個線程的精確狀態信息。
JAVA 線程的背景資料 線程同步一個線程可以與其他線程在同一時間內被處理。為了確保一致性,當多個線程試圖使用共享資源的時候,通過使用 hread synchronization 在同一時間內,應該只有一個線程能訪問共享資源
JAVA 中的線程同步可以使用監視器,每個 JAVA 對象都有一個多帶帶的監視器,這個監視器僅僅只能被一個線程擁有,對于擁有一個由不同的線程所擁有的監視器的線程,確實需要在隊列中等待,以便其他線程釋放它的監視器。
線程狀態為了分析一個 thread dump 文件,你需要知道線程狀態。線程情況在 java.lang.Thread.State 中闡明了。
圖1:線程狀態
NEW:線程剛被創建,但是還沒有被處理。
RUNNABLE:線程占用了 CPU 并且處理了一個任務。(或是是在等待狀態由于操作系統的資源分配)
BLOCKED:該線程正在等待另外的不同的線程釋放鎖,以便獲取監視器鎖
WAITING:該線程正在等待,通過使用了 wait, join 或者是 park 方法
TIMED_WAITING:該線程正在等待,通過使用了 sleep, wait, join 或者是 park 方法。(這個與 WAITING 不同是通過方法參數指定了最大等待時間,WAITING 可以通過時間或者是外部的變化解除)
線程類型JAVA 的線程類型分為以下兩種:
daemon threads;
非 daemon threads。
Daemon threads 將停止工作當沒有其他任何非 Daemon threads 時。即使你不創建任何線程,JAVA 應用也將默認創建幾個線程。他們大部分是 daemon threads。主要用于任務處理比如內存回收或者是 JMX。
一個運行 static void main(String[] args) 方法的線程被作為非 daemon threads 線程創建,并且當該線程停止工作的時候,所有任何其他 daemon threads 也將停止工作。(這個運行在 main 方法中的線程被稱為 VM thread in HotSpot VM)
獲取一個 Thread Dump我們將介紹三種最常用的方法,記住,有非常多的其他方法可以獲取thread dump,一個 thread dump 僅僅只能在測量的時候顯示線程狀態。因此為了看得線程狀態的變化,建議每隔5秒提取5到10次的記錄。
使用 jstack 獲取 Thread Dump在 JDK1.6 或者是更高的版本中,通過使用 jstack, 在 MS Windows 平臺上可能可以獲取到 Thread Dump。
通過使用 jps 檢查當前正在運行的JAVA進程的 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 的參數來獲取 thread dumps。
[user@linux ~]$ jstack -f 5824使用 jVisualVM 生成 Thread Dump
通過使用一個程序 jVisualVM 來生成 Thread Dump。
如上圖在左側的任務表示當前正在運行的進程列表,點擊你想要信息的那個線程,然后選擇 thread tab 頁來檢查實時的線程信息。點擊右邊的 Thread Dump 按鈕來獲取 thread dump 文件。
在 Linux 控制臺生成通過使用 ps -ef 命令來獲取當前正在運行的 JAVA 應用程序的進程 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) 的參數來獲取 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)
線程名字:當使用 Java.lang.Thread 類生成一個線程的時候,該線程將被命名為 Thread-(Number)。但是當使用 java.util.concurrent.ThreadFactory 類的時候,它將被命名為 pool-(number)-thread-(number)。
優先級:代表該線程的優先級
線程 ID:代表該線程的唯一 ID,(一些有用的信息,比如該線程的 CPU 使用率或者是內存使用率,都能通過該線程 ID 獲取到)。
線程狀態:代表該線程當前的狀態
線程調用棧:代表該線程的調用棧信息
Thread Dump Patterns by Type When Unable to Obtain a Lock (BLOCKED)這個應用程序的整體性能下降是因為一個線程占用了鎖阻止了其他線程獲得鎖,在下面的示例中,BLOCKED_TEST pool-1-thread-1 線程占用了 <0x0000000780a000b0> 鎖,然而 BLOCKED_TEST pool-1-thread-2 和 BLOCKED_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)當在死鎖狀態
這是當線程 A 需要獲取線程 B 的鎖來繼續它的任務,然而線程 B 也需要獲取線程 A 的鎖來繼續它的任務的時候發生的。在 thread dump 中,你能看到 DEADLOCK_TEST-1 線程持有 0x00000007d58f5e48 鎖,并且嘗試獲取 0x00000007d58f5e60 鎖。你也能看到 DEADLOCK_TEST-2 線程持有 0x00000007d58f5e60,并且嘗試獲取 0x00000007d58f5e78,同時 DEADLOCK_TEST-3 線程持有 0x00000007d58f5e78,并且在嘗試獲取 0x00000007d58f5e48 鎖,如你所見,每個線程都在等待獲取另外一個線程的鎖,這狀態將不會被改變直到一個線程丟棄了它的鎖。
"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當持續等待從遠處服務器接收消息
該線程是正常的,因為它的狀態為 RUNNABLE,盡管如此,當你按照時間順序排列 Thread Dump,你會發現 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)當 Waiting 時
線程保持在 Waiting 狀態,在 Thread Dump 中,IoWaitThread 線程保持等待狀態來從 LinkedBlockingQueue 接收消息。如果 LinkedBlockingQueue 一直沒有消息,該線程的狀態將不會改變。
當線程的資源不能正常的被組織
"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)
不必要的線程會堆積起來,當線程的資源不能被正常的組織的話,如果這個發送了,建議監控線程組織過程或檢查線程終止的條件。
使用 Thread Dump 怎樣解決問題 示例1:當 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
從這個應用中,發現使用 CPU 最高的線程。
獲取使用 CPU 最多的輕量級進程(LWP),把它的唯一標示碼 (10039) 轉換成十六進制 (0x2737)。
然后獲取進程的 Thread Dump,檢查進程的動作。
通過 PID 10029 來提取應用程序的 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,然后檢查線程的狀態來確定問題。
示例2:當進程的性能異常的慢多次獲得 thread dumps 后,找出 BLOCKED 狀態的線程列表。
" 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 狀態的線程列表。
如果線程是 BLOCKED 的,提取線程嘗試獲取的相關聯的鎖。
通過 thread dumps,你能確定線程狀態停止在 BLOCKED,因為鎖 <0xe0375410> 不能被獲取到,這個問題可以通過分析當前夯住的線程的 stack trace 來解決。
使用 DBMS 的時候,為什么以上的范例經常出現再應用程序中,這有兩個原因。第一個原因是配置不當。盡管事實是該線程仍然在工作,它們不能展示它們最好的性能,因為 DBCP 的配置文件沒有配置正確。如果你多次提取 thread dumps 并且對比它們,你將經常看到被阻塞的線程之前處于不同的狀態。
第二個原因是不正常的連接。當與 DBMS 的連接保持在不正常的狀態,線程將等待直到超時。在這個例子中,通過多次提取 thread dumps 并對比它們,你會發現與 DBMS 相關的線程仍然在阻塞狀態。通過適當改變一些值,比如超時時間,你可以縮短問題發生的時間。
為簡單的 Thread Dump 命名線程編碼當使用 java.lang.Thread 對象創建線程的時候,線程被命名為 Thread-(Number) 。當使用 java.util.concurrent.DefaultThreadFactory 對象創建線程的時候,線程被命名為 named pool-(Number)-thread-(Number)。當為應用程序分析成百上千的線程的時候,如果線程依然用它們默認的名字,分析它們將變得非常困難,因為這是非常難以辨別這些線程來分析的。
因此,你被建議開發一個命名線程的規則當一個新線程被創建的時候。
當你使用 java.lang.Thread 創建線程,你可以通過創建參數給該線程定義個約定俗成的名字。
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);
當你使用 java.util.concurrent.ThreadFactory 創建線程的時候,你可以通過生成你自己的線程工廠來命名它,如果你不需要特別的功能性,你可以使用 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使用 MBean 獲取更多的細節信息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 來獲取 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 來提取阻塞線程或者是等待線程花費的時間。并利用這一點,你也可以得到那些處于非活動狀態的時間異常長的線程列表。
總結在本文中,我關注的是為開發人員提供了大量的多線程編程經驗,本素材可能是常識。對于經驗較少的開發人員來說,我覺得我直接跳過 thread dumps,不提供足夠的關于 thread activities 的背景知識。這是由于我的知識缺乏,所以我不能很清晰的簡潔明了的解釋 thread activities。我衷心的希望本文能給很多開發人員提供幫助。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/64133.html
摘要:前兩天,開源了一個內存泄露自動探測神器,它是一個和的內存泄露檢測庫,可以大幅度減少了開發中遇到的問題,對于開發者來說,無疑是個福音,下面對該庫的進行簡單的翻譯小漏不補沉大船。隨著時間過去越來越多熟知的內存泄露問題被制造商在開源項目中修復。 前兩天,Square開源了一個內存泄露自動探測神器——LeakCanary,它是一個Android和Java的內存泄露檢測庫,可以大幅度減少了開發中...
摘要:線程可以被稱為輕量級進程。一個守護線程是在后臺執行并且不會阻止終止的線程。其他的線程狀態還有,和。上下文切換是多任務操作系統和多線程環境的基本特征。在的線程中并沒有可供任何對象使用的鎖和同步器。 原文:Java Multi-Threading and Concurrency Interview Questions with Answers 翻譯:并發編程網 - 鄭旭東 校對:方騰飛 多...
摘要:現在終止一個線程,基本上只能靠曲線救國式的中斷來實現。中斷機制的核心在于中斷狀態和異常中斷狀態設置一個中斷狀態清除一個中斷狀態方法同時會返回線程原來的中斷的狀態。中斷異常中斷異常一般是線程被中斷后,在一些類型的方法如中拋出。 前言 系列文章目錄 線程中斷是一個很重要的概念,通常,取消一個任務的執行,最好的,同時也是最合理的方法,就是通過中斷。 本篇我們主要還是通過源碼分析來看看中斷的概...
閱讀 2007·2021-11-24 10:45
閱讀 1865·2021-10-09 09:43
閱讀 1303·2021-09-22 15:38
閱讀 1230·2021-08-18 10:19
閱讀 2850·2019-08-30 15:55
閱讀 3070·2019-08-30 12:45
閱讀 2975·2019-08-30 11:25
閱讀 365·2019-08-29 11:30