死锁的必要条件
判断死锁的必要条件通常包括以下几点:
- 互斥条件:资源只能被一个进程(或线程)占有,无法被其他进程共享。
- 请求与保持条件:一个进程在请求新资源的同时,保持对已分配资源的占有。
- 不可剥夺条件:资源不能被强制从占有者手中回收,只能由占有者自愿释放。
- 循环等待条件:存在一个进程(或线程)等待序列,其中每个进程都在等待下一个进程释放资源。
生动而形象的例子
现在桌上摆着一把锤子, 一把扳手 // 互斥条件
我拿到了左手拿到一把锤子, 这时我准备去拿扳手 // 请求与保持条件
可这时我发现扳手被拿去开啤酒了, 而且他还想拿我的锤子开核桃
我不打算放弃, 你这拿去开啤酒开核桃明显不合理, // 不可剥夺条件,除非打架
我可是打算拿着锤子跟扳手去跟隔壁班花约会的
于是为了跟班花完美的约会, 于是我在这里等扳手
两个人一直耗到海枯石烂, 隔壁班花也有了自己的孩子 // 循环等待条件
于是你感慨死锁真是害人呀, 不说了, 继续等扳手了
Java 中的死锁示例
java">public class DeadlockExample {
public static void main(String[] args) {
final Object lock1 = new Object();
final Object lock2 = new Object();
Thread t1 = new Thread(new Runnable() {
@Override
public void run() {
synchronized (lock1) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (lock2) {
System.out.println("Thread 1 is holding lock 1 and lock 2.");
}
}
}
});
Thread t2 = new Thread(new Runnable() {
@Override
public void run() {
synchronized (lock2) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (lock1) {
System.out.println("Thread 2 is holding lock 1 and lock 2.");
}
}
}
});
t1.start();
t2.start();
}
}
在上述代码中,有两个线程 t1 和 t2,它们同时试图获取 lock1 和 lock2 两个对象的锁,但获取锁的顺序不同。假设 t1 先获取了 lock1 的锁,然后在试图获取 lock2 的锁时被阻塞,而此时 t2 已经获取了 lock2 的锁,并试图获取 lock1 的锁,但 lock1 的锁已经被 t1 占用,因此 t2 也会被阻塞。这时候就产生了死锁,t1 和 t2 互相等待对方释放锁,导致程序无法继续执行。