能快速定位死锁和cpu 100%源头:先用jps -l获取pid,再jstack -l 抓带锁快照,末尾found 1 deadlock即确认死锁;top -hp 找高cpu线程,转十六进制后匹配nid=0x...,聚焦runnable线程的at行定位代码。

直接用 jstack -l <pid></pid> 抓快照,再结合 top -Hp 找高 CPU 线程,就能快速定位死锁和 CPU 100% 的真实源头。关键不在命令本身,而在抓得准、看得清、比得快。
先锁定目标 Java 进程 PID
没 PID 就没法操作。常用方式是:
-
jps -l:最简洁,列出所有 Java 进程及其主类或 JAR 路径 -
ps aux | grep java或jps -lv:当进程名模糊时,靠启动参数区分多个实例 - 注意权限:jstack 必须由与目标 JVM 相同用户执行,容器里尤其容易因用户不一致报 Unable to open socket file
抓取带锁信息的线程快照
普通 jstack <pid></pid> 只输出栈,无法判断锁关系。必须加 -l:
-
jstack -l <pid> > threaddump.log</pid>:保存完整快照,结尾会自动检查死锁 - 有
Found 1 deadlock.就说明 JVM 已确认死锁,直接看最后一段——很多人只翻前面几百行,漏掉这行就白忙 - JDK 8u60+ 可加
-e查 native 堆栈,对排查 JNI 或底层 IO 阻塞有帮助 - 生产环境慎用
-F(强制 dump),可能引发短暂 STW,且结果未必可靠
快速识别死锁位置
死锁区块里每条线程都明确标出:
-
locked:当前持有的锁地址 -
waiting to lock:正阻塞等待的锁地址 - 两个线程的 locked 和 waiting 地址交叉出现(如 A 持 0x123 等 0x456,B 持 0x456 等 0x123),就是死锁证据
- 对应源码位置看
at com.xxx.Service.method(Service.java:88)这类行,前提是编译时保留了 debug info(Maven 默认开启)
定位 CPU 100% 的具体线程和代码
CPU 高通常不是“卡住”,而是“狂跑”。重点盯 RUNNABLE 状态线程:
-
top -Hp <pid></pid>:按 P 排序,找出 CPU 占用最高的线程 TID(十进制) -
printf "%x\n" <tident></tident>:转成十六进制,比如 12345 →0x3039 -
jstack <pid> | grep "nid=0x3039" -A20</pid>:精准提取该线程栈,看最顶上几行在执行什么 - 典型高 CPU 场景:无限循环、正则回溯、大对象 JSON 序列化、极端 hash 冲突下的 HashMap 操作、未设 limit 的 Stream.collect
- 注意区分:GCTaskThread 或 ConcurrentMarkThread 大量 RUNNABLE 是 GC 导致,不是业务代码问题
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











