一文详解Java中死锁产生原因、常见场景及排查解决思路(附详细案例代码)
·
01-死锁的概念
死锁是指两个或两个以上的线程在执行过程中,因抢夺资源而造成的一种互相等待的现象,若无外力干涉,则它们无法再继续推进下去
02-产生原因
- 系统资源不足
- 进程运行推进顺序不合适
- 系统资源分配不当

03-常见死锁场景与示例
3.1 嵌套锁顺序不一致
public class DeadLockDemo {
static Object a = new Object();
static Object b = new Object();
public static void main(String[] args) {
new Thread(() -> {
synchronized (a){
System.out.println("t1线程持有a锁,试图获取b锁");
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (b){
System.out.println("t1线程获取到b锁");
}
}
},"t1").start();
new Thread(() -> {
synchronized (b){
System.out.println("t2线程持有a锁,试图获取a锁");
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (a){
System.out.println("t2线程获取到a锁");
}
}
},"t2").start();
}
}
分析:
- t1线程执行:先获取
a锁,再请求b锁 - t2线程执行:先获取
b锁,再请求a锁 - 可能形成循环等待
3.2 动态锁顺序死锁
public void transfer(Account from, Account to, int amount) {
synchronized (from) {
synchronized (to) {
from.withdraw(amount);
to.deposit(amount);
}
}
}
分析:
如果两个线程同时调用transfer(),但参数顺序相反:
- 线程A:
transfer(account1, account2, 100) - 线程B:
transfer(account2, account1, 200)
可能产生死锁
3.3 资源死锁(如线程池任务相互等待)
ExecutorService executor = Executors.newFixedThreadPool(2);
Future<?> future1 = executor.submit(() -> {
Future<?> future2 = executor.submit(() -> System.out.println("Task2"));
future2.get(); // 等待任务2完成
});
future1.get(); // 等待任务1完成
分析:
- 线程池只有两个线程
- 任务1提交任务2并等待任务2完成,任务2等待线程池空闲
- 若任务2无法执行,任务1也无法完成,形成死锁
04-如何避免死锁
4.1 固定锁顺序
始终按全局一致顺序获取锁
public void transfer(Account a, Account b, int amount) {
Object firstLock = a.id < b.id ? a : b;
Object secondLock = a.id < b.id ? b : a;
synchronized (firstLock) {
synchronized (secondLock) {
// 操作
}
}
}
4.2 使用超时机制
用tryLock()替代synchronized,设置超时时间
if (lock1.tryLock(100, TimeUnit.MILLISECONDS)) {
try {
if (lock2.tryLock(100, TimeUnit.MILLISECONDS)) {
try {
// 操作
} finally {
lock2.unlock();
}
}
} finally {
lock1.unlock();
}
}
4.3 避免嵌套锁
尽量只持有一个锁,或 将多个锁封装为一个大锁
05-如何排查死锁
5.1 纯命令
- jps -l —> 相当于 java ps -ef -l —> 查看本地系统中所有正在运行的 Java 进程
- jstack 进程编号 —> 查看进程堆栈信息

5.2 图形化
jconsole —> win + R 输入 jconsole,连接对应的Java进程,点击线程,点击检测死锁 即可查看

更多推荐
所有评论(0)