考虑下面这个专门为说明多线程中的死锁现象而构造的程序:
import java.util.LinkedList;
public class Stack {
public static void main(String[] args) {
final Stack stack = new Stack();
new Thread("push") {
@Override
public void run() {
for(int i = 0; i < 100; i++)
{
try {
Thread.sleep(10);
} catch (InterruptedException e) {}
stack.push("object " + i);
}
}
}.start();
new Thread("pop") {
@Override
public void run() {
for(int i = 0; i < 100; i++)
{
try {
System.out.println(stack.pop());
} catch (Exception e) {}
}
}
}.start();
}
LinkedList<Object> list = new LinkedList<Object>();
public synchronized void push(Object x) {
System.out.println("begin to push " + x);
synchronized (list) {
list.addLast(x);
notify();
}
System.out.println("end to push " + x);
}
public synchronized Object pop() throws Exception {
System.out.println("begin to pop");
synchronized (list) {
if (list.size() <= 0) {
wait();
}
return list.removeLast();
}
}
}
该程序构造了一个 Stack,启动了两个线程。一个线程向 Stack 中添加数据,另外一个线程从 Stack 中取出数据并打印。但是运行程序后就会发现程序输出:
begin to pop
begin to push object 0
后,在再也没有后续输出了。
2. Dump 并分析线程状态
启动 jvisualvm 查看该程序线程的状态,将其 Dump,就可以得到以下结果:
"pop" prio=6 tid=0x02b11800 nid=0x3648 in Object.wait() [0x02eaf000..0x02eafd14] java.lang.Thread.State: WAITING (on object monitor) at java.lang.Object.wait(Native Method)
- waiting on <0x22ee0000> (a Stack)
at java.lang.Object.wait(Object.java:485) at Stack.pop(Stack.java:44) - locked <0x22ee0010> (a java.util.LinkedList)
- locked <0x22ee0000> (a Stack)
at Stack$2.run(Stack.java:24)
Locked ownable synchronizers:
- None
"push" prio=6 tid=0x02b28800 nid=0x4120 waiting for monitor entry [0x02e5f000..0x02e5fd94] java.lang.Thread.State: BLOCKED (on object monitor) at Stack.push(Stack.java:35) - waiting to lock <0x22ee0010> (a java.util.LinkedList)
- locked <0x22ee0000> (a Stack)
at Stack$1.run(Stack.java:14)
Locked ownable synchronizers:
- None
可以看到,pop 线程正在运行 wait(); 语句,处于 WAITING 状态,同时,该线程锁住了 list 和 stack 对象。push 线程处于 BLOCKED 状态,等待其他线程释放 list 对象。
3. 运行过程及死锁原因分析
责任编辑:小草