前言
在多线程编程中,死锁(Deadlock) 是一个常见且棘手的问题。当多个线程因竞争资源而陷入无限等待的状态时,程序将无法继续执行,导致系统性能下降甚至崩溃。本文将通过原理分析、代码示例和解决方案,帮助你深入理解Java死锁及其应对策略。
一、什么是死锁?
1.1 死锁的定义
当两个或多个线程永久阻塞,每个线程都在等待被其他线程占用的资源时,系统进入死锁状态。此时若无外力介入,程序将无法继续执行。
1.2 死锁的原理
死锁的发生需要同时满足以下四个必要条件(Coffman条件):
- 互斥条件(Mutual Exclusion):资源一次只能被一个线程占用。
- 占有且等待(Hold and Wait):线程持有资源的同时等待其他资源。
- 不可抢占(No Preemption):资源只能由持有者主动释放。
- 循环等待(Circular Wait):多个线程形成互相等待的环形链。
二、典型死锁场景与代码示例
2.1 经典的锁顺序死锁
场景描述
两个线程(Thread1和Thread2)需要获取两把锁(LockA和LockB),但加锁顺序不同,导致互相等待。
public class ClassicDeadlock {
private static final Object lockA = new Object();
private static final Object lockB = new Object();
public static void main(String[] args) {
new Thread(() -> {
synchronized (lockA) {
System.out.println("Thread1 holds lockA");
try {
Thread.sleep(100); } catch (InterruptedException e) {
}
synchronized (lockB) {
System.out.println("Thread1 acquired lockB");
}
}
}).start();
new Thread(() -> {
synchronized (lockB) {
System.out.println("Thread2 holds lockB"