2014年4月29日星期二

Java_009:Thread Dump 中线程状态的含义(摘录+整理)

Thread Dump 是当前Java进程的一个快照,打印出所有线程的状态和调用堆栈,以及 Monitor的状态。
在不同的操作系统下,产生thread dump的方式是不同的。
(1)Windows 环境
在启动程序的控制台里输入:Ctrl + Break,thread dump会产生在标准输出中。
(2)Linux 环境
在启动程序的控制台里输入:Ctrl + \,thread dump会产生在标准输出中。
或者在另外一个终端中输入:kill -3 [pid],thread dump会产生在启动程序的标准输出中。
(3)在终端输入:jstack [pid],jstack是JDK5.0以后增加的查看某个java进程的线程信息命令。

以JBoss EAP 6.2为例,我们来看看一个Java thread dump的基本样子:

2014-04-29 14:28:08
Full thread dump Java HotSpot(TM) 64-Bit Server VM (24.51-b03 mixed mode):

说明:这部分可以看到thread dump的时间,JVM的信息

"Attach Listener" daemon prio=5 tid=0x00007f907901b000 nid=0x5c07 runnable [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

说明:"Attach Listener"是一个JVM内部的后台线程。

"Thread-71" prio=5 tid=0x00007f9074cfe800 nid=0x10403 runnable [0x00000001194f9000]
   java.lang.Thread.State: RUNNABLE
at sun.nio.ch.KQueueArrayWrapper.kevent0(Native Method)
at sun.nio.ch.KQueueArrayWrapper.poll(KQueueArrayWrapper.java:200)
at sun.nio.ch.KQueueSelectorImpl.doSelect(KQueueSelectorImpl.java:103)
at sun.nio.ch.SelectorImpl.lockAndDoSelect(SelectorImpl.java:87)
- locked <0x00000007ed189fd8> (a sun.nio.ch.Util$2)
- locked <0x00000007ed189fc8> (a java.util.Collections$UnmodifiableSet)
- locked <0x00000007ed189ea8> (a sun.nio.ch.KQueueSelectorImpl)
at sun.nio.ch.SelectorImpl.select(SelectorImpl.java:98)
at org.jboss.sun.net.httpserver.ServerImpl$Dispatcher.run(ServerImpl.java:382)
at java.lang.Thread.run(Thread.java:744)

说明:这是一个用户进程,是我们最需要关心的进程。
(1)线程 name: "Thread-71"
(2)线程优先级: prio=5
(3)java线程的标识:tid=0x00007f9074cfe800
(4)native线程的标识: nid= 0x10403
(5)线程的状态:runnable
(6)线程栈起始地址:[0x00000001194f9000] 

那么,Java thread dump中的线程状态都有哪些,它们的含义各是什么呢?

1.  runnable:执行中
一般指该线程正在执行状态中,该线程占用了资源,正在处理某个请求,有可能正在传递SQL到数据库执行,有可能在对某个文件操作,有可能进行数据类型等转换。

2. waiting on condition:等待资源(需重点关注) 
等待某个资源或等待某个条件的发生,可能情况有:
(1)读取某资源,且该资源采用了资源锁的情况下,线程进入等待状态,等待资源的读取。
比如,如果发现大量线程都在处在 wait on condition,并且从线程 stack看,发现都在等待网络读写,则这是一个网络瓶颈,因为网络阻塞导致线程无法执行,具体原因还要进一步分析。
一种可能情况是网络非常忙,几乎消耗了所有的带宽,仍然有大量数据等待网络读写;
另一种可能情况是网络空闲,但由于路由等问题,导致包无法正常的到达。
(2)正在等待其他线程的执行。
(3)线程正在sleep。

3. waiting on monitor entry:等待获取Monitor(需重点关注)
在dump中找到等待获取Monitor对应的对象地址,比如0x00000000acf4d0c0,如果发现有大量线程都在等待给这个地址上锁,那么这个对象就是引起性能瓶颈的原因。
继续在dump中寻找,看看线程获得了这个对象能在日志里找到谁获得了这个锁,如发现locked 0x00000000acf4d0c0 字样,就可以进一步分析了。

4. in Object.wait() :对象等待中 

关于Monitor的含义
Monitor是 Java中用以实现线程之间的互斥与协作的主要手段,它可以看成是对象或者 Class的锁。每一个对象都有,也仅有一个 Monitor。
从下图可以看出,每个 Monitor在某个时刻,只能被一个线程拥有,该线程就是“Active Thread”,而其它线程都是“Waiting Thread”,分别在两个队列“ Entry Set”和“Wait Set”里面等候。在“Entry Set”中等待的线程状态是“Waiting for monitor entry”;在“Wait Set”中等待的线程状态是“in Object.wait()”。
在“ Entry Set”里面的线程都等待拿到Monitor,拿到了线程就成为了Runnable线程,否则就会一直处于处于“waiting for monitor entry”。
在 “Wait Set”里面的线程都如饥似渴地等待拿到Monitor。那么它们他是怎么进入到“Wait Set”的呢?
当一个线程拿到了Monitor,但是在其他资源没有到位的情况下,调用同步锁对象(一般是synchronized()内的对象)的 wait() 方法,放弃了 Monitor,它就进入到了 “Wait Set”队列。只有当其他线程通过notify() 或者 notifyAll(),释放了同步锁后,这个线程才会有机会重新去竞争Monitor。在stack中,它表现的状态是in Object.wait()。


参考文献:
1. http://www.blogjava.net/jzone/articles/303979.html
2. http://go-on.iteye.com/blog/1673894
3. http://www.cnblogs.com/zhengyun_ustc/archive/2013/01/06/dumpanalysis.html
4. http://www.cnblogs.com/tomsheep/archive/2010/06/09/1754419.html
5. http://www.blogjava.net/jzone/articles/303979.html

1 条评论:

trustno1 说...

针对业余爱好者的java swing编程
向图像添加文本