死锁是指两个或多个线程在执行过程中,因争夺资源而造成的一种互相等待的现象。要编写一段必定会产生死锁的代码,需要满足以下四个条件(死锁的必要条件):
- 互斥条件:资源一次只能被一个线程占用。
- 占有并等待:线程持有至少一个资源,并等待获取其他被占用的资源。
- 非抢占条件:线程已持有的资源不能被其他线程强行抢占,只能由线程自己释放。
- 循环等待条件:存在一个线程等待的循环链,每个线程都在等待下一个线程所持有的资源。
以下是一个必定会产生死锁的Java代码示例:
public class DeadlockExample {
private static final Object lock1 = new Object();
private static final Object lock2 = new Object();
public static void main(String[] args) {
Thread thread1 = new Thread(() -> {
synchronized (lock1) {
System.out.println("Thread 1: Holding lock 1...");
// 尝试获取 lock2
synchronized (lock2) {
System.out.println("Thread 1: Holding lock 1 and lock 2...");
}
}
});
Thread thread2 = new Thread(() -> {
synchronized (lock2) {
System.out.println("Thread 2: Holding lock 2...");
// 尝试获取 lock1
synchronized (lock1) {
System.out.println("Thread 2: Holding lock 2 and lock 1...");
}
}
});
thread1.start();
thread2.start();
}
}
代码解析
- 互斥条件:
lock1
和lock2
是两个互斥资源,一次只能被一个线程占用。
- 占有并等待:
thread1
持有lock1
,并尝试获取lock2
。thread2
持有lock2
,并尝试获取lock1
。
- 非抢占条件:
thread1
不会主动释放lock1
,除非它成功获取lock2
。thread2
不会主动释放lock2
,除非它成功获取lock1
。
- 循环等待条件:
thread1
在等待thread2
释放lock2
。thread2
在等待thread1
释放lock1
。
运行结果
运行上述代码后,程序会进入死锁状态,控制台输出类似于以下内容:
Thread 1: Holding lock 1...
Thread 2: Holding lock 2...
之后程序会一直卡住,因为两个线程都在等待对方释放锁,导致死锁。
如何避免死锁?
在实际开发中,可以通过以下方式避免死锁:
- 按顺序获取锁:所有线程按照相同的顺序获取锁。
- 超时释放:尝试获取锁时设置超时时间,超时后释放已持有的锁。
- 死锁检测:通过算法检测死锁,并强制释放资源。
例如,修改上述代码,让两个线程按照相同的顺序获取锁:
Thread thread1 = new Thread(() -> {
synchronized (lock1) {
System.out.println("Thread 1: Holding lock 1...");
synchronized (lock2) {
System.out.println("Thread 1: Holding lock 1 and lock 2...");
}
}
});
Thread thread2 = new Thread(() -> {
synchronized (lock1) {
System.out.println("Thread 2: Holding lock 1...");
synchronized (lock2) {
System.out.println("Thread 2: Holding lock 1 and lock 2...");
}
}
});
这样就不会产生死锁。
THE END
暂无评论内容