线程A当前持有互斥所锁lock1,线程B当前持有互斥锁lock2。接下来,当线程A仍然持有lock1时,它试图获取lock2,因为线程B正持有lock2,因此线程A会阻塞等待线程B对lock2的释放。如果此时线程B在持有lock2的时候,也在试图获取lock1,因为线程A正持有lock1,因此线程B会阻塞等待A对lock1的释放。二者都在等待对方所持有锁的释放,而二者却又都没释放自己所持有的锁,这时二者便会一直阻塞下去。这种情形称为死锁。
下列代码演示了死锁:
public class ThreadDeadlock {
public static void main(String[] args) {
Object obj1 = new Object();
Object obj2 = new Object();
Object obj3 = new Object();
Thread t1 = new Thread(new SyncThread(obj1, obj2), "t1");
Thread t2 = new Thread(new SyncThread(obj2, obj3), "t2");
Thread t3 = new Thread(new SyncThread(obj3, obj1), "t3");
try {
t1.start();
Thread.sleep(1000);
t2.start();
Thread.sleep(1000);
t3.start();
} catch (InterruptedException e) {
System.out.println("失败!");
}
try {
Thread.sleep(15000);
System.out.println("试图中断死锁的线程t1");
t1.interrupt();
System.out.println("试图中断死锁的线程t2");
t2.interrupt();
System.out.println("试图中断死锁的线程t3");
t3.interrupt();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
class SyncThread implements Runnable {
private Object obj1;
private Object obj2;
public SyncThread(Object o1, Object o2) {
this.obj1 = o1;
this.obj2 = o2;
}
@Override
public void run() {
String name = Thread.currentThread().getName();
System.out.println("线程" + name + " 准备获取" + obj1 + " 的锁 ");
synchronized (obj1) {
System.out.println("线程" + name + " 已经获取" + obj1 + " 的锁 ");
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("线程" + name + " 准备获取" + obj2 + " 的锁 ");
synchronized (obj2) {
System.out.println("线程" + name + " 已经获取" + obj2 + " 的锁 ");
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
运行结果如下:
线程t1 准备获取java.lang.Object@1102fab 的锁
线程t1 已经获取java.lang.Object@1102fab 的锁
线程t2 准备获取java.lang.Object@16f5b17 的锁
线程t2 已经获取java.lang.Object@16f5b17 的锁
线程t3 准备获取java.lang.Object@b950d1 的锁
线程t3 已经获取java.lang.Object@b950d1 的锁
线程t1 准备获取java.lang.Object@16f5b17 的锁
线程t2 准备获取java.lang.Object@b950d1 的锁
线程t3 准备获取java.lang.Object@1102fab 的锁
试图中断死锁的线程t1
试图中断死锁的线程t2
试图中断死锁的线程t3
由于t1,t2,t3三个线程分别持有了obj1 ,obj2,obj3的互斥锁。
接下来需要分别获取obj2,obj3,obj1锁,而该锁已分别被t2,t3,t1线程持有。发生死锁现象,调用Thread.interrupt()方法试图中断线程,却发现线程仍然在继续运行。
避免死锁是一件困难的事,遵循以下原则有助于规避死锁:
1、能够原子性的获取需要的多个锁;
2、调整对多个锁的获取顺序;