Java and Thread

一个 web 服务器使用几十到几百个线程来处理大量并发用户,如果一个或多个线程使用相同的资源,线程之间的竞争就不可避免了,并且有时候可能会发生死锁。

Thread contention 是一个线程等待锁的一个状态,这个锁被另外一个线程持有,等待被释放,不同的线程频繁访问 WEB 应用的共享资源。例如,记录一条日志,线程尝试记录日志之前必须先获取锁来访问共享资源。

死锁是线程竞争的一个特殊状态,一个或是多个线程在等待其他线程完成它们的任务为了完成它们自己的任务。

线程竞争会引起各种不同的问题,为了分析这些这些问题,你需要使用 dump threadsdump 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 的线程类型分为以下两种:

  1. daemon threads;
  2. 非 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。

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

使用明确的 PID 作为 jstack 的参数来获取 thread dumps

  1. [user@linux ~]$ jstack -f 5824

使用 jVisualVM 生成 Thread Dump

通过使用一个程序 jVisualVM 来生成 Thread Dump

如上图在左侧的任务表示当前正在运行的进程列表,点击你想要信息的那个线程,然后选择 thread tab 页来检查实时的线程信息。点击右边的 Thread Dump 按钮来获取 thread dump 文件。

在 Linux 控制台生成

通过使用 ps -ef 命令来获取当前正在运行的 JAVA 应用程序的进程 ID。

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

使用精确的 pid 作为 kill –SIGQUIT(3) 的参数来获取 thread dump

Thread Dump 文件的 线程信息

  1. "pool-1-thread-13" prio=6 tid=0x000000000729a000 nid=0x2fb4 runnable [0x0000000007f0f000] java.lang.Thread.State: RUNNABLE
  2. at java.net.SocketInputStream.socketRead0(Native Method)
  3. at java.net.SocketInputStream.read(SocketInputStream.java:129)
  4. at sun.nio.cs.StreamDecoder.readBytes(StreamDecoder.java:264)
  5. at sun.nio.cs.StreamDecoder.implRead(StreamDecoder.java:306)
  6. at sun.nio.cs.StreamDecoder.read(StreamDecoder.java:158)
  7. - locked <0x0000000780b7e688> (a java.io.InputStreamReader)
  8. at java.io.InputStreamReader.read(InputStreamReader.java:167)
  9. at java.io.BufferedReader.fill(BufferedReader.java:136)
  10. at java.io.BufferedReader.readLine(BufferedReader.java:299)
  11. - locked <0x0000000780b7e688> (a java.io.InputStreamReader)
  12. 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 正在等待获取锁。

  1. "BLOCKED_TEST pool-1-thread-1" prio=6 tid=0x0000000006904800 nid=0x28f4 runnable [0x000000000785f000]
  2. java.lang.Thread.State: RUNNABLE
  3. at java.io.FileOutputStream.writeBytes(Native Method)
  4. at java.io.FileOutputStream.write(FileOutputStream.java:282)
  5. at java.io.BufferedOutputStream.flushBuffer(BufferedOutputStream.java:65)
  6. at java.io.BufferedOutputStream.flush(BufferedOutputStream.java:123)
  7. - locked <0x0000000780a31778> (a java.io.BufferedOutputStream)
  8. at java.io.PrintStream.write(PrintStream.java:432)
  9. - locked <0x0000000780a04118> (a java.io.PrintStream)
  10. at sun.nio.cs.StreamEncoder.writeBytes(StreamEncoder.java:202)
  11. at sun.nio.cs.StreamEncoder.implFlushBuffer(StreamEncoder.java:272)
  12. at sun.nio.cs.StreamEncoder.flushBuffer(StreamEncoder.java:85)
  13. - locked <0x0000000780a040c0> (a java.io.OutputStreamWriter)
  14. at java.io.OutputStreamWriter.flushBuffer(OutputStreamWriter.java:168)
  15. at java.io.PrintStream.newLine(PrintStream.java:496)
  16. - locked <0x0000000780a04118> (a java.io.PrintStream)
  17. at java.io.PrintStream.println(PrintStream.java:687)
  18. - locked <0x0000000780a04118> (a java.io.PrintStream)
  19. at com.nbp.theplatform.threaddump.ThreadBlockedState.monitorLock(ThreadBlockedState.java:44)
  20. - locked <0x0000000780a000b0> (a com.nbp.theplatform.threaddump.ThreadBlockedState)
  21. at com.nbp.theplatform.threaddump.ThreadBlockedState$1.run(ThreadBlockedState.java:7)
  22. at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886)
  23. at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908)
  24. at java.lang.Thread.run(Thread.java:662)
  25. Locked ownable synchronizers:
  26. - <0x0000000780a31758> (a java.util.concurrent.locks.ReentrantLock$NonfairSync)
  27. "BLOCKED_TEST pool-1-thread-2" prio=6 tid=0x0000000007673800 nid=0x260c waiting for monitor entry [0x0000000008abf000]
  28. java.lang.Thread.State: BLOCKED (on object monitor)
  29. at com.nbp.theplatform.threaddump.ThreadBlockedState.monitorLock(ThreadBlockedState.java:43)
  30. - waiting to lock <0x0000000780a000b0> (a com.nbp.theplatform.threaddump.ThreadBlockedState)
  31. at com.nbp.theplatform.threaddump.ThreadBlockedState\$2.run(ThreadBlockedState.java:26)
  32. at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886)
  33. at java.util.concurrent.ThreadPoolExecutor\$Worker.run(ThreadPoolExecutor.java:908)
  34. at java.lang.Thread.run(Thread.java:662)
  35. Locked ownable synchronizers:
  36. - <0x0000000780b0c6a0> (a java.util.concurrent.locks.ReentrantLock$NonfairSync)
  37. "BLOCKED_TEST pool-1-thread-3" prio=6 tid=0x00000000074f5800 nid=0x1994 waiting for monitor entry [0x0000000008bbf000]
  38. java.lang.Thread.State: BLOCKED (on object monitor)
  39. at com.nbp.theplatform.threaddump.ThreadBlockedState.monitorLock(ThreadBlockedState.java:42)
  40. - waiting to lock <0x0000000780a000b0> (a com.nbp.theplatform.threaddump.ThreadBlockedState)
  41. at com.nbp.theplatform.threaddump.ThreadBlockedState\$3.run(ThreadBlockedState.java:34)
  42. at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886
  43. at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908)
  44. at java.lang.Thread.run(Thread.java:662)
  45. Locked ownable synchronizers:
  46. - <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 锁,如你所见,每个线程都在等待获取另外一个线程的锁,这状态将不会被改变直到一个线程丢弃了它的锁。

  1. "DEADLOCK_TEST-1" daemon prio=6 tid=0x000000000690f800 nid=0x1820 waiting for monitor entry [0x000000000805f000]
  2. java.lang.Thread.State: BLOCKED (on object monitor)
  3. at com.nbp.theplatform.threaddump.ThreadDeadLockState$DeadlockThread.goMonitorDeadlock(ThreadDeadLockState.java:197)
  4. - waiting to lock <0x00000007d58f5e60> (a com.nbp.theplatform.threaddump.ThreadDeadLockState$Monitor)
  5. at com.nbp.theplatform.threaddump.ThreadDeadLockState$DeadlockThread.monitorOurLock(ThreadDeadLockState.java:182)
  6. - locked <0x00000007d58f5e48> (a com.nbp.theplatform.threaddump.ThreadDeadLockState$Monitor)
  7. at com.nbp.theplatform.threaddump.ThreadDeadLockState$DeadlockThread.run(ThreadDeadLockState.java:135)
  8. Locked ownable synchronizers:
  9. - None
  10. "DEADLOCK_TEST-2" daemon prio=6 tid=0x0000000006858800 nid=0x17b8 waiting for monitor entry [0x000000000815f000]
  11. java.lang.Thread.State: BLOCKED (on object monitor)
  12. at com.nbp.theplatform.threaddump.ThreadDeadLockState$DeadlockThread.goMonitorDeadlock(ThreadDeadLockState.java:197)
  13. - waiting to lock <0x00000007d58f5e78> (a com.nbp.theplatform.threaddump.ThreadDeadLockState$Monitor)
  14. at com.nbp.theplatform.threaddump.ThreadDeadLockState$DeadlockThread.monitorOurLock(ThreadDeadLockState.java:182)
  15. - locked <0x00000007d58f5e60> (a com.nbp.theplatform.threaddump.ThreadDeadLockState$Monitor)
  16. at com.nbp.theplatform.threaddump.ThreadDeadLockState$DeadlockThread.run(ThreadDeadLockState.java:135)
  17. Locked ownable synchronizers:
  18. - None
  19. "DEADLOCK_TEST-3" daemon prio=6 tid=0x0000000006859000 nid=0x25dc waiting for monitor entry [0x000000000825f000]
  20. java.lang.Thread.State: BLOCKED (on object monitor)
  21. at com.nbp.theplatform.threaddump.ThreadDeadLockState$DeadlockThread.goMonitorDeadlock(ThreadDeadLockState.java:197)
  22. - waiting to lock <0x00000007d58f5e48> (a com.nbp.theplatform.threaddump.ThreadDeadLockState$Monitor)
  23. at com.nbp.theplatform.threaddump.ThreadDeadLockState$DeadlockThread.monitorOurLock(ThreadDeadLockState.java:182)
  24. - locked <0x00000007d58f5e78> (a com.nbp.theplatform.threaddump.ThreadDeadLockState$Monitor)
  25. at com.nbp.theplatform.threaddump.ThreadDeadLockState$DeadlockThread.run(ThreadDeadLockState.java:135)
  26. Locked ownable synchronizers:
  27. - None

当持续等待从远处服务器接收消息

该线程是正常的,因为它的状态为 RUNNABLE,尽管如此,当你按照时间顺序排列 Thread Dump,你会发现socketReadThread 线程正在无限等待读取 socket。

  1. "socketReadThread" prio=6 tid=0x0000000006a0d800 nid=0x1b40 runnable [0x00000000089ef000]
  2. java.lang.Thread.State: RUNNABLE
  3. at java.net.SocketInputStream.socketRead0(Native Method)
  4. at java.net.SocketInputStream.read(SocketInputStream.java:129)
  5. at sun.nio.cs.StreamDecoder.readBytes(StreamDecoder.java:264)
  6. at sun.nio.cs.StreamDecoder.implRead(StreamDecoder.java:306)
  7. at sun.nio.cs.StreamDecoder.read(StreamDecoder.java:158)
  8. - locked <0x00000007d78a2230> (a java.io.InputStreamReader)
  9. at sun.nio.cs.StreamDecoder.read0(StreamDecoder.java:107)
  10. - locked <0x00000007d78a2230> (a java.io.InputStreamReader)
  11. at sun.nio.cs.StreamDecoder.read(StreamDecoder.java:93)
  12. at java.io.InputStreamReader.read(InputStreamReader.java:151)
  13. at com.nbp.theplatform.threaddump.ThreadSocketReadState$1.run(ThreadSocketReadState.java:27)
  14. at java.lang.Thread.run(Thread.java:662)

当 Waiting 时

线程保持在 Waiting 状态,在 Thread Dump 中,IoWaitThread 线程保持等待状态来从 LinkedBlockingQueue 接收消息。如果 LinkedBlockingQueue 一直没有消息,该线程的状态将不会改变。

  1. "IoWaitThread" prio=6 tid=0x0000000007334800 nid=0x2b3c waiting on condition [0x000000000893f000]
  2. java.lang.Thread.State: WAITING (parking)
  3. at sun.misc.Unsafe.park(Native Method)
  4. - parking to wait for <0x00000007d5c45850> (a java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject)
  5. at java.util.concurrent.locks.LockSupport.park(LockSupport.java:156)
  6. at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await(AbstractQueuedSynchronizer.java:1987)
  7. at java.util.concurrent.LinkedBlockingDeque.takeFirst(LinkedBlockingDeque.java:440)
  8. at java.util.concurrent.LinkedBlockingDeque.take(LinkedBlockingDeque.java:629)
  9. at com.nbp.theplatform.threaddump.ThreadIoWaitState$IoWaitHandler2.run(ThreadIoWaitState.java:89)
  10. at java.lang.Thread.run(Thread.java:662)

当线程的资源不能正常的被组织

不必要的线程会堆积起来,当线程的资源不能被正常的组织的话,如果这个发送了,建议监控线程组织过程或检查线程终止的条件。

使用 Thread Dump 怎样解决问题

示例1:当 CPU 利用率高的异常

  1. 提取获取最高 CPU 使用率的线程。
  1. [user@linux ~]$ ps -mo pid.lwp.stime.time.cpu -C java
  2. PID LWP STIME TIME %CPU
  3. 10029 - Dec07 00:02:02 99.5
  4. - 10039 Dec07 00:00:00 0.1
  5. - 10040 Dec07 00:00:00 95.5

从这个应用中,发现使用 CPU 最高的线程。

获取使用 CPU 最多的轻量级进程(LWP),把它的唯一标示码 (10039) 转换成十六进制 (0x2737)。

  1. 然后获取进程的 Thread Dump,检查进程的动作。

通过 PID 10029 来提取应用程序的 Thread Dump,然后通过一个 nid 0x2737 来找到这个线程。

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

每个小时的几个时间提取 Thread Dump,然后检查线程的状态来确定问题。

示例2:当进程的性能异常的慢

多次获得 thread dumps 后,找出 BLOCKED 状态的线程列表。

  1. " DB-Processor-13" daemon prio=5 tid=0x003edf98 nid=0xca waiting for monitor entry [0x000000000825f000]
  2. java.lang.Thread.State: BLOCKED (on object monitor)
  3. at beans.ConnectionPool.getConnection(ConnectionPool.java:102)
  4. - waiting to lock <0xe0375410> (a beans.ConnectionPool)
  5. at beans.cus.ServiceCnt.getTodayCount(ServiceCnt.java:111)
  6. at beans.cus.ServiceCnt.insertCount(ServiceCnt.java:43)
  7. "DB-Processor-14" daemon prio=5 tid=0x003edf98 nid=0xca waiting for monitor entry [0x000000000825f020]
  8. java.lang.Thread.State: BLOCKED (on object monitor)
  9. at beans.ConnectionPool.getConnection(ConnectionPool.java:102)
  10. - waiting to lock <0xe0375410> (a beans.ConnectionPool)
  11. at beans.cus.ServiceCnt.getTodayCount(ServiceCnt.java:111)
  12. at beans.cus.ServiceCnt.insertCount(ServiceCnt.java:43)
  13. " DB-Processor-3" daemon prio=5 tid=0x00928248 nid=0x8b waiting for monitor entry [0x000000000825d080]
  14. java.lang.Thread.State: RUNNABLE
  15. at oracle.jdbc.driver.OracleConnection.isClosed(OracleConnection.java:570)
  16. - waiting to lock <0xe03ba2e0> (a oracle.jdbc.driver.OracleConnection)
  17. at beans.ConnectionPool.getConnection(ConnectionPool.java:112)
  18. - locked <0xe0386580> (a java.util.Vector)
  19. - locked <0xe0375410> (a beans.ConnectionPool)
  20. at beans.cus.Cue_1700c.GetNationList(Cue_1700c.java:66)
  21. 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 创建线程,你可以通过创建参数给该线程定义个约定俗成的名字。

  1. public Thread(Runnable target, String name);
  2. public Thread(ThreadGroup group, String name);
  3. public Thread(ThreadGroup group, Runnable target, String name);
  4. public Thread(ThreadGroup group, Runnable target, String name, long stackSize);

当你使用 java.util.concurrent.ThreadFactory 创建线程的时候,你可以通过生成你自己的线程工厂来命名它,如果你不需要特别的功能性,你可以使用 MyThreadFactory 作为以下描述:

  1. import java.util.concurrent.ConcurrentHashMap;
  2. import java.util.concurrent.ThreadFactory;
  3. import java.util.concurrent.atomic.AtomicInteger;
  4. public class MyThreadFactory implements ThreadFactory {
  5. private static final ConcurrentHashMap<String, AtomicInteger> POOL_NUMBER =
  6. new ConcurrentHashMap<String, AtomicInteger>();
  7. private final ThreadGroup group;
  8. private final AtomicInteger threadNumber = new AtomicInteger(1);
  9. private final String namePrefix;
  10. public MyThreadFactory(String threadPoolName) {
  11. if (threadPoolName == null) {
  12. throw new NullPointerException("threadPoolName");
  13. }
  14. POOL_NUMBER.putIfAbsent(threadPoolName, new AtomicInteger());
  15. SecurityManager securityManager = System.getSecurityManager();
  16. group = (securityManager != null) ? securityManager.getThreadGroup() :
  17. Thread.currentThread().getThreadGroup();
  18. AtomicInteger poolCount = POOL_NUMBER.get(threadPoolName);
  19. if (poolCount == null) {
  20. namePrefix = threadPoolName + " pool-00-thread-";
  21. } else {
  22. namePrefix = threadPoolName + " pool-" + poolCount.getAndIncrement() + "-thread-";
  23. }
  24. }
  25. public Thread newThread(Runnable runnable) {
  26. Thread thread = new Thread(group, runnable, namePrefix + threadNumber.getAndIncrement(), 0);
  27. if (thread.isDaemon()) {
  28. thread.setDaemon(false);
  29. }
  30. if (thread.getPriority() != Thread.NORM_PRIORITY) {
  31. thread.setPriority(Thread.NORM_PRIORITY);
  32. }
  33. return thread;
  34. }
  35. }

使用 MBean 获取更多的细节信息

你可以使用 MBean 来获取 ThreadInfo 对象。你也可以获取更加多通过 thread dumps 不能获取的信息。通过使用ThreadInfo

  1. ThreadMXBean mxBean = ManagementFactory.getThreadMXBean();
  2. long[] threadIds = mxBean.getAllThreadIds();
  3. ThreadInfo[] threadInfos =
  4. mxBean.getThreadInfo(threadIds);
  5. for (ThreadInfo threadInfo : threadInfos) {
  6. System.out.println(
  7. threadInfo.getThreadName());
  8. System.out.println(
  9. threadInfo.getBlockedCount());
  10. System.out.println(
  11. threadInfo.getBlockedTime());
  12. System.out.println(
  13. threadInfo.getWaitedCount());
  14. System.out.println(
  15. threadInfo.getWaitedTime());
  16. }

你可以使用方法 ThreadInfo 来提取阻塞线程或者是等待线程花费的时间。并利用这一点,你也可以得到那些处于非活动状态的时间异常长的线程列表。

[转]Java Thread Dump 性能分析的更多相关文章

  1. 三个实例演示 Java Thread Dump 日志分析

    原文地址: http://www.cnblogs.com/zhengyun_ustc/archive/2013/01/06/dumpanalysis.html jstack Dump 日志文件中的线程 ...

  2. 三个实例演示 Java Thread Dump 日志分析(转)

    原文链接:http://www.cnblogs.com/zhengyun_ustc/archive/2013/01/06/dumpanalysis.html 转来当笔记^_^ jstack Dump ...

  3. Java Thread dump 日志分析

    jstack Dump 日志文件中的线程状态 dump 文件里,值得关注的线程状态有: 死锁,Deadlock(重点关注)  执行中,Runnable 等待资源,Waiting on conditio ...

  4. java thread dump日志分析

    jstack Dump 日志文件中的线程状态 dump 文件里,值得关注的线程状态有: 死锁,Deadlock(重点关注)  执行中,Runnable 等待资源,Waiting on conditio ...

  5. 性能分析之-- JAVA Thread Dump 分析综述

    性能分析之-- JAVA Thread Dump 分析综述       一.Thread Dump介绍 1.1什么是Thread Dump? Thread Dump是非常有用的诊断Java应用问题的工 ...

  6. Java应用常用性能分析工具

    Java应用常用性能分析工具 好的工具有能有效改善和提高工作效率或加速分析问题的进度,笔者将从事Java工作中常用的性能工具和大家分享下,如果感觉有用记得投一票哦,如果你有好的工具也可以分享给我 工具 ...

  7. 性能分析之– JAVA Thread Dump 分析

    最近在做性能测试,需要对线程堆栈进行分析,在网上收集了一些资料,学习完后,将相关知识整理在一起,输出文章如下. 一.Thread Dump介绍 1.1什么是Thread Dump? Thread Du ...

  8. (转)性能分析之-- JAVA Thread Dump 分析综述

    原文链接:http://blog.csdn.net/rachel_luo/article/details/8920596 最近在做性能测试,需要对线程堆栈进行分析,在网上收集了一些资料,学习完后,将相 ...

  9. [JAVA]JAVA章4 Thread Dump如何分析

    一.Thread Dump介绍 1.1什么是Thread Dump? Thread Dump是非常有用的诊断Java应用问题的工具.每一个Java虚拟机都有及时生成所有线程在某一点状态的thread- ...

随机推荐

  1. pyenv 以及 virtualenv

    244 pyenv global 3.5.1 245 which python 246 python 247 pip install virtualenv 248 ls 249 pwd 250 ls ...

  2. 改变placeholder颜色

    /* WebKit browsers */ ::-webkit-input-placeholder { color: red; text-overflow: ellipsis; } /* Mozill ...

  3. &#x开头的是什么编码呢。浏览器可以解释它。如&#20013;&#22269;等同与中文"中国"?

    形如—— &#dddd; &#xhhhh; &#name; ——的一串字符是 HTML.XML 等 SGML 类语言的转义序列(escape sequence).它们不是「编码 ...

  4. Gradle用户指南(1)-Gradle安装

    前置条件 Gradle 需要 Java JDK 或者 JRE,版本是 6 及以上.Gradle 将会装载自己的 Groovy 库,因此,Groovy 不需要被安装.任何存在的 Groovy 安装都会被 ...

  5. motto7

    与其羡慕别人,还不如模仿别人的过程.

  6. RHEL6.4记录一次添加一块新分区的操作

    首先看了下挂载点及目录 fdisk /dev/sda [root@box ~]# fdisk /dev/sda WARNING: DOS-compatible mode is deprecated. ...

  7. 理解css中的line-height

    在css中,line-height有下面五种可能的值:我们来看看w3c中列出如下可能值: normal:默认,设置合理的行间距. number:设置数字,此数字会与当前的字体尺寸相乘来设置行间距. l ...

  8. 响应式js幻灯片代码一枚

    网站搭建经常会用到js幻灯片轮播,放上几张上档次的美图,为你的爱站增添大气元素.经常看到一些js幻灯片代码,但是感觉不是很美观,有的也不支持自适应缩放,也即是响应式,现在智能手机的普及以及移动浏览器技 ...

  9. linux 查看系统信息命令(比较全)

    linux 查看系统信息命令是linux初学者必备的基础知识, 这些命令也非常有用, 因为进入linux第一件事就可能是首先查看系统信息, 因此必要的系统的学习一下这些linux系统信息命令还是非常有 ...

  10. django 架构点点滴滴

    前言: 零星发现一些,零星记录一些,因此可能整体比较混乱,因为显然不是一气呵成写的. 关于CBV(Class Based View): 首先吐槽下,cbv的整体继承结构,可真的不是很优美,可以查看这里 ...