Java多线程死锁是多个线程互相等待对方持有的锁而形成的必然僵局,必须同时满足互斥、持有并等待、不可剥夺、循环等待四个条件;破坏任一条件即可预防,其中统一加锁顺序是最有效手段。

Java 多线程死锁本质是多个线程互相等待对方持有的锁,谁也不放手,结果全部卡住不动。它不是偶发异常,而是满足四个条件时必然发生的系统级僵局。
死锁是怎么产生的
必须同时满足以下四个条件:
- 互斥条件:锁资源一次只能被一个线程持有(比如 synchronized 锁对象)
- 持有并等待:线程已持有一把锁,又去申请另一把锁,且不释放手头的锁
- 不可剥夺:锁不能被其他线程强行抢走,只能由持有者主动退出同步块或调用 unlock()
- 循环等待:线程 A 等 B 的锁,B 又等 A 的锁,形成闭环
典型代码场景:线程1先 synchronized(lockA),再 synchronized(lockB);线程2反着来——先 lockB 再 lockA。只要两个线程执行节奏刚好错开(比如中间 sleep 一下),就极大概率死锁。
怎么快速排查死锁
最常用、最可靠的方式是用 JDK 自带工具,无需加依赖、不重启服务:
将后端 Java 接口文档转换为前端 TypeScript 类型定义(interface / type)。输入:飞书文档、Spring Boot 接口文档、Swagger/OpenAPI、手写 API 文档等。输出:包含请求参数与响应结果的 .md 文件,含完整 JSDoc 注释。触发关键词:Java 转 TS、接口转换、生成前端类型、接口文档转 TypeScript、DTO/VO/BO 转 interface、后端文档转前端类型、生成接口类型、类型定义生成。
- 终端执行 jps -l 找到目标 Java 进程 ID(如 8923)
- 执行 jstack 8923 > dump.txt 抓取线程快照
- 打开 dump.txt,直接搜索关键词 “Found one Java-level deadlock” ——JDK 会自动标出哪几个线程在等谁、持有什么锁、在哪行代码卡住
如果想更直观:用 JConsole 连上进程 → 切到“线程”页 → 点“检测死锁”,立刻高亮显示死锁线程和完整调用栈;VisualVM 装 Threads Inspector 插件后效果类似。
怎么解决和预防死锁
核心思路是破坏上述四个条件中的任意一个,实践中最可行的是从设计层面切断循环等待:
- 统一加锁顺序:所有线程按固定规则获取锁,比如按对象哈希值排序(lockA.hashCode()
-
使用带超时的锁:改用
ReentrantLock.tryLock(long, TimeUnit),设定最多等 3 秒,超时就释放已占锁并重试/报错,避免无限等待 - 减少锁粒度与嵌套:避免在一个 synchronized 块里再进另一个;优先用局部变量、无状态设计,能不用锁就不用
- 避免锁内调用外部方法:防止被回调进未知逻辑,意外触发新锁或死循环
注意:synchronized 是可重入锁,同一个线程重复加同一把锁不会死锁,但跨线程争不同锁的场景它无法规避。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










