线上java应用死锁表现为响应变慢、cpu不高但业务卡住,需用jstack初筛(查“found one java-level deadlock”或连续三次对比线程栈)和arthas精准定位(thread -b一键检测并标出代码行号),再通过验证加锁顺序、缩小锁粒度或改用trylock修复。

线上 Java 应用出现死锁时,响应变慢、CPU 不高但业务卡住,关键是要快速区分“死锁”和“锁竞争”,并选对工具——jstack 适合初步定性,Arthas 才是高效定位的主力。
先确认是不是死锁
死锁有明确特征:多个线程互相等待对方持有的锁,状态长期停留在 BLOCKED 或 WAITING,且无进展。jstack 输出中若看到 “Found one Java-level deadlock” 就基本可定性。但注意:jstack 在 JDK 8u60 之前对 ReentrantLock 的 owner 线程识别不准,可能只显示 AbstractOwnableSynchronizer,看不出具体谁占着锁。
更稳妥的做法是连续执行三次 jstack(间隔 5–10 秒),对比线程栈是否“固定不动”。如果相同线程反复卡在同一个 synchronized 块或 lock() 调用点,就高度可疑。
jstack 快速抓取与初筛
在 Linux 终端直接执行:
- jps -l 查出目标 Java 进程 PID
-
jstack -l
> thread_dump.log 导出带锁信息的线程快照 - 用 grep -A 10 -B 5 "BLOCKED\|waiting for" 快速过滤可疑线程
- 重点看堆栈里是否出现成对的锁获取顺序颠倒,比如线程 A 先 lock1 再 lock2,线程 B 先 lock2 再 lock1
Arthas 实时精准定位
相比 jstack 的静态快照,Arthas 可以交互式追踪,5 分钟内完成从连接到定位:
-
java -jar arthas-boot.jar 启动后选择目标进程(生产环境建议加
--target-ip限制访问) - 执行 dashboard:3 秒内看到实时线程视图,重点关注 CPU% 高但状态为 BLOCKED 的线程,以及 BLOCKED 数量突增
- 执行 thread -b:一键检测死锁,自动列出所有死锁线程、持有锁者、等待锁者,并标出代码行号(如
OrderService.java:47) - 对单个可疑线程,用 thread
查看完整堆栈,确认锁对象 hash(如 java.lang.Object@6d4b1c02)是否一致
定位后怎么验证和修复
找到死锁点后,别急着改代码,先验证逻辑:
- 检查两个线程的加锁顺序是否不一致——这是死锁最常见原因
- 确认锁粒度是否过大,比如整个方法用同一把锁,而实际只需保护某段临界区
- 考虑用 tryLock + 超时机制替代无条件 lock(),避免无限等待
- 对多资源场景,统一约定全局加锁顺序(如按 resource ID 升序获取)
修复后,建议在线上小流量灰度验证,再全量发布。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











