dump 文件里,值得关注的线程状态有:
- 死锁,Deadlock(重点关注)
- 执行中,Runnable
- 等待资源,Waiting on condition(重点关注)
- 等待获取监视器,Waiting on monitor entry(重点关注)
- 暂停,Suspended
- 对象等待中,Object.wait() 或 TIMED_WAITING
- 阻塞,Blocked(重点关注)
- 停止,Parked
Runnable:不解释
Wait on condition:该状态出现在线程等待某个条件的发生。具体是什么原因,可以结合 stacktrace来分析。最常见的情况是线程在等待网络的读写。如果网络数据没准备好,线程就等待在那里。另外一种出现 Wait on condition的常见情况是该线程在 sleep,等待 sleep的时间到了时候,将被唤醒。
Waiting for monitor entry 和 in Object.wait():这两种情况在多线程的情况下经常出现。Java是通过Monitor来实现线程互斥和协作(有些把Monitor直译成锁,我认为不妥,不是还有Lock嘛)。具体Monitor的深入理解见 http://www.cnblogs.com/tomsheep/archive/2010/06/09/1754419.html
但是可以理解成Monitor是一个对象或者class所拥有的锁,每个对象和class有且仅有一个。见下图.
每个 Monitor在某个时刻,只能被一个线程拥有,该线程就是 “Active Thread”,而其它线程都是 “Waiting Thread”,分别在两个队列 “ Entry Set”和 “Wait Set”里面等候。
在 “ Entry Set”里面的线程都等待拿到Monitor,拿到了线程就成为了Runnable线程,否则就会一直处于处于 “waiting for monitor entry”。一段代码作为例子
public class MyThread implements Runnable{ public void run() { synchronized(this) { for (int i = 0; i < 1; i--) { System.out.println(Thread.currentThread().getName() + " synchronized loop " + i); } } } public static void main(String[] args) { MyThread t1 = new MyThread(); Thread ta = new Thread(t1, "A"); Thread tb = new Thread(t1, "B"); ta.start(); tb.start(); } }
大家一看就知道,B线程肯定是“千年老二“,永远拿不到Monitor了。
对应的stack:
"B" prio=10 tid=0x0969a000 nid=0x11d6 waiting for monitor entry [0x8bb22000] java.lang.Thread.State: BLOCKED (on object monitor) at org.marshal.MyThread.run(MyThread.java:7) - waiting to lock <0x94757078> (a org.marshal.MyThread) at java.lang.Thread.run(Thread.java:636) "A" prio=10 tid=0x09698800 nid=0x11d5 runnable [0x8bb73000] java.lang.Thread.State: RUNNABLE at java.io.FileOutputStream.writeBytes(Native Method) at java.io.FileOutputStream.write(FileOutputStream.java:297) at java.io.BufferedOutputStream.flushBuffer(BufferedOutputStream.java:82) at java.io.BufferedOutputStream.flush(BufferedOutputStream.java:140) - locked <0x947571b0> (a java.io.BufferedOutputStream) at java.io.PrintStream.write(PrintStream.java:449) - locked <0x94757190> (a java.io.PrintStream) at sun.nio.cs.StreamEncoder.writeBytes(StreamEncoder.java:220) at sun.nio.cs.StreamEncoder.implFlushBuffer(StreamEncoder.java:290) at sun.nio.cs.StreamEncoder.flushBuffer(StreamEncoder.java:103) - locked <0x947572a0> (a java.io.OutputStreamWriter) at java.io.OutputStreamWriter.flushBuffer(OutputStreamWriter.java:185) at java.io.PrintStream.write(PrintStream.java:494) - locked <0x94757190> (a java.io.PrintStream) at java.io.PrintStream.print(PrintStream.java:636) at java.io.PrintStream.println(PrintStream.java:773) - locked <0x94757190> (a java.io.PrintStream) at org.marshal.MyThread.run(MyThread.java:8) - locked <0x94757078> (a org.marshal.MyThread) at java.lang.Thread.run(Thread.java:636)
<0x94757078> 就是两个线程争夺的Monitor
在 “Wait Set”里面的线程都如饥似渴地等待拿到Monitor。他们是怎么进入到“Wait Set”的呢?当一个线程拿到了Monitor,但是在其他资源没有到位的情况下,调用同步锁对象(一般是synchronized()内的对象)的 wait() 方法,放弃了 Monitor,它就进入到了 “Wait Set”队列。只有当其他线程通过notify() 或者 notifyAll(),释放了同步锁后,这个线程才会有机会重新去竞争Monitor。在stack中,它表现的状态是in Object.wait()。修改上面的代码public class WaitThread implements Runnable{
public void run() { synchronized(this) { try { this.wait(); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } public static void main(String[] args) { WaitThread t1 = new WaitThread(); Thread ta = new Thread(t1, "A"); Thread tb = new Thread(t1, "B"); ta.start(); tb.start(); }
对应的stack:
"B" prio=10 tid=0x08173000 nid=0x1304 in Object.wait() [0x8baf2000] java.lang.Thread.State: WAITING (on object monitor) at java.lang.Object.wait(Native Method) - waiting on <0xa9cb50e0> (a org.marshal.WaitThread) at java.lang.Object.wait(Object.java:502) at org.marshal.WaitThread.run(WaitThread.java:8) - locked <0xa9cb50e0> (a org.marshal.WaitThread) at java.lang.Thread.run(Thread.java:636) "A" prio=10 tid=0x08171c00 nid=0x1303 in Object.wait() [0x8bb43000] java.lang.Thread.State: WAITING (on object monitor) at java.lang.Object.wait(Native Method) - waiting on <0xa9cb50e0> (a org.marshal.WaitThread) at java.lang.Object.wait(Object.java:502) at org.marshal.WaitThread.run(WaitThread.java:8) - locked <0xa9cb50e0> (a org.marshal.WaitThread) at java.lang.Thread.run(Thread.java:636)
A和B线程都进入了”wait set“。B线程也拿到过这个Monitor,因为A线程释放过了,这也验证上面的话,他们都在等待得而复失的<0xa9cb50e0>
转自 http://go-on.iteye.com/blog/1673894