死锁是多线程竞争资源导致的互相等待现象,需满足互斥、占有等待、不可剥夺和循环等待四个条件;Java中常见于线程以不同顺序获取多个锁,如线程1持lock1等lock2,线程2持lock2等lock1;可通过按序加锁、设置超时、减少锁范围、避免嵌套锁及使用jstack工具检测来有效预防。

死锁是指两个或多个线程在执行过程中,因争夺资源而造成的一种互相等待的现象,导致这些线程都无法继续执行下去。
死锁发生的条件
死锁的产生必须同时满足以下四个条件,缺一不可:
- 互斥条件:某个资源一次只能被一个线程占用。
- 占有并等待:线程已经持有了至少一个资源,但又申请新的资源,而该资源被其他线程占用,此时该线程阻塞,但不释放已持有的资源。
- 不可剥夺条件:线程已获得的资源在未使用完之前不能被其他线程强行抢占。
- 循环等待条件:存在一个线程和资源的循环等待链,比如线程 A 等待线程 B 占用的资源,线程 B 又等待线程 A 占用的资源。
Java 中死锁的常见场景
在 Java 多线程编程中,死锁通常发生在多个线程以不同的顺序获取多个锁。例如:
Object lock1 = new Object();
Object lock2 = new Object();
// 线程1
new Thread(() -> {
synchronized (lock1) {
System.out.println("Thread1 获取 lock1");
try { Thread.sleep(100); } catch (InterruptedException e) {}
synchronized (lock2) {
System.out.println("Thread1 获取 lock2");
}
}
}).start();
// 线程2
new Thread(() -> {
synchronized (lock2) {
System.out.println("Thread2 获取 lock2");
try { Thread.sleep(100); } catch (InterruptedException e) {}
synchronized (lock1) {
System.out.println("Thread2 获取 lock1");
}
}
}).start();
在这个例子中,线程1先拿 lock1 再申请 lock2,线程2先拿 lock2 再申请 lock1。如果两个线程几乎同时运行,就可能造成线程1持有 lock1 等 lock2,线程2持有 lock2 等 lock1,从而形成死锁。
自从百度屏蔽淘宝客网站、淘宝抛弃淘宝客之后,个人站长集体陷入了恐慌之中。此时,什么值得买网的异军突起引起了广大个人站长的极大关注。做一个什么值得买一样的导购网站成了众多个人站长的一致心愿! TP-COUPON 导购系统 即是让个人站长实现此心愿的绝佳选择! 欢迎个人站长选用。V1.1版 更新记录:1.修正请求时查询淘宝店铺错误的bug2.删除一些无用的代码
立即学习“Java免费学习笔记(深入)”;
如何避免死锁
可以通过以下方式预防或避免死锁:
- 按顺序加锁:所有线程以相同的顺序请求资源。例如都先获取 lock1 再获取 lock2。
-
使用超时机制:尝试使用
tryLock(long timeout)方法,在指定时间内无法获取锁就放弃,避免无限等待。 - 减少锁的范围:尽量缩短同步代码块,只在必要时才持有锁。
- 避免嵌套锁:尽量不要在一个 synchronized 块中再去获取另一个锁。
- 使用工具检测:利用 jstack 等工具分析线程堆栈,排查死锁问题。










