jstack 可自动检测并标出死锁:先用 jps -l 获取 PID,再执行 jstack -l ,输出末尾若出现“Found 1 deadlock.”即表明存在死锁,并清晰列出相互等待的线程、锁对象及持有关系。

Java 中用 jstack 检测线程死锁非常直接:只需运行命令,jstack 会自动扫描并明确标出死锁线程。关键在于正确触发和解读输出。
确认进程 ID(PID)
先找到目标 Java 进程的 PID,常用方式:
- Linux/macOS:执行
ps -ef | grep java或jps -l - Windows:执行
jps -l(需 JDK 的 bin 目录在 PATH 中)
注意区分多个 Java 进程,避免分析错实例。如果应用以服务方式运行(如 systemd 或 Windows Service),可查日志或服务管理命令获取 PID。
执行 jstack 并启用死锁检测
直接运行以下命令(无需额外参数,jstack 默认检查死锁):
立即学习“Java免费学习笔记(深入)”;
使用约定式提交(Conventional Commits)生成标准化的 Git 提交信息。适用于以下场景: (1) 暂存更改时需要提交信息; (2) 审查 diff 时希望获得结构化摘要; (3) 编写 PR 描述或变更日志(changelog)条目; (4) 用户明确要求“为本次更改编写提交信息”。 该功能会分析已暂存/未暂存的 diff,并生成按类型(type)划分范围的提交信息。
-
jstack <pid></pid>—— 输出全部线程栈,末尾若存在死锁,会以 "Found 1 deadlock." 开头单独列出 -
jstack -l <pid></pid>—— 推荐使用,-l会显示锁信息(如java.util.concurrent.locks.ReentrantLock)和等待/持有详情,对定位Lock类死锁更有效
输出中死锁段结构清晰:包含死锁线程名、状态(BLOCKED)、正在等待的锁、已持有的锁,以及互相依赖关系。
识别典型死锁输出特征
关注 jstack 输出末尾类似这样的区块:
<font color="red">Found 1 deadlock.</font> Deadlock detected: ===================== Thread-1: waiting to lock Monitor@0x00007f8b4c00a2e0 (object in first line of stack trace), which is held by Thread-0 Thread-0: waiting to lock Monitor@0x00007f8b4c00a350 (object in first line of stack trace), which is held by Thread-1
或者针对 ReentrantLock:
- 出现
java.util.concurrent.locks.ReentrantLock$NonfairSync等字样 - 线程状态为
WAITING或BLOCKED,且堆栈中含lock()、tryLock()调用 -
-l输出中能看到owned by和waiting for明确指向对方线程
配合代码快速定位问题点
拿到死锁线程栈后,重点看每条线程最顶部的几行 Java 方法调用(即阻塞发生的位置):
- 比对两个(或多个)线程各自试图获取的锁对象(如 synchronized 锁的 this / class / 某个实例,或 ReentrantLock 实例)
- 检查是否按不同顺序获取了同一组锁(例如:线程 A 先锁 obj1 再锁 obj2;线程 B 先锁 obj2 再锁 obj1)
- 注意静态同步方法、类锁与实例锁混用、嵌套锁等易忽略场景
小技巧:把 jstack 输出保存为文本(jstack -l PID > thread_dump.txt),用编辑器搜索 "deadlock" 或线程名,能更快聚焦。

















