线上CPU飙到100%?别慌,这3个工具比top快10倍!
正准备下班,手机突然疯狂震动------生产环境CPU告警!你SSH登上服务器,习惯性地敲下
top
命令,然后按H切换到线程视图,找到最高CPU的线程,记下PID,转成16进制,再jstack
...等你一套操作敲完,5秒过去了,CPU使用率已经降下来了。线索,就这样在指尖溜走。
🔥 传统方法的最大问题
说起定位Java应用CPU使用率高的问题,大部分人的第一反应是:top
+ jstack
。
完整流程是这样的:
bash
# 第一步:找到Java进程
top
# 第二步:切换到线程视图
按 H 键
# 第三步:记下最高CPU的线程ID(比如12345)
# 第四步:转16进制
printf "%x\n" 12345
# 输出:3039
# 第五步:dump线程栈
jstack <pid> > thread.txt
# 第六步:在文件中搜索 nid=0x3039
grep -A 20 "nid=0x3039" thread.txt
看起来很专业?但有三个致命问题:
1. 命令长,记不住
老实说,你能背下printf "%x\n"
这个16进制转换命令吗?反正我每次都要Google一下。遇到线上问题紧张得不行,大脑容易空白,这种命令根本记不住。
2. 流程长,容易出错
6个步骤,任何一步出错都要重来。线程ID记错了?16进制转换算错了?grep的时候少打个0?每一步都是坑。
3. 时机错过,白忙一场
这是最要命的。
CPU飙高往往是瞬时的------可能是某个定时任务触发,可能是流量突增,也可能是GC导致。等你把上面这6步命令敲完,5秒过去了,CPU使用率已经降下来,线程栈里根本看不出问题所在。
就像拿着相机想拍流星,结果还在调焦距,流星已经没了。
我去年就遇到过一次:电商大促期间,订单服务CPU间歇性飙到90%,每次持续2-3秒。等我SSH登上去,top刚打开,CPU就降下来了。来来回回折腾了半小时,一无所获,最后只能扩容服务器硬抗。
那次之后,我决定找更快的工具。
🚀 工具1:show-busy-java-threads.sh - 一键救场
为什么推荐它?
show-busy-java-threads.sh
是一个Shell脚本,把上面那6步操作自动化了。一行命令,秒级出结果。
完整的脚本链接,关注公众号回复
thread
可下载。
真实案例:秒级定位死循环
去年有一次,推荐服务的CPU突然飙到300%(4核机器),持续了10多分钟。用户反馈首页加载特别慢。
我第一时间想到了这个脚本:
bash
# 直接运行,不需要传任何参数
./show-busy-java-threads.sh
瞬间结果就出来了:
scss
[1] Busy(57.0%) thread(23645/0x5c5d) stack of java process(23630):
"recommendation-worker-3" #123 daemon prio=5 os_prio=0 tid=0x00007f8a1c0a1000 nid=0x5c5d runnable
at com.company.recommend.ContentFilter.isValid(ContentFilter.java:156)
at com.company.recommend.RecommendEngine.filter(RecommendEngine.java:89)
at com.company.recommend.RecommendEngine.process(RecommendEngine.java:45)
...
[2] Busy(55.2%) thread(23648/0x5c60) stack of java process(23630):
"recommendation-worker-6" #126 daemon prio=5 os_prio=0 tid=0x00007f8a1c0a3800 nid=0x5c60 runnable
at com.company.recommend.ContentFilter.isValid(ContentFilter.java:156)
...
一眼就看出来了:
- 多个工作线程都卡在
ContentFilter.isValid
这个方法的156行 - CPU占用分别是57%和55%
打开代码一看,第156行是个正则表达式匹配,而且是在一个没有break的循环里...找到问题了!
从发现问题到定位代码,很快就搞定。
使用方法
1. 运行脚本:
bash
# 自动识别Java进程,显示最繁忙的5个线程
./show-busy-java-threads.sh
# 显示最繁忙的10个线程
./show-busy-java-threads.sh -c 10
# 指定Java进程ID
./show-busy-java-threads.sh -p 12345
# 持续监控模式,每3秒刷新一次
./show-busy-java-threads.sh -c 5 -i 3
2. 输出解读:
脚本会输出:
- 线程ID(十进制和十六进制)
- CPU占用百分比
- 完整的线程栈
- 自动高亮显示业务代码
优势:
- ✅ 不用记命令,一行搞定
- ✅ 不用转16进制,自动完成
- ✅ 不用grep,直接显示
- ✅ 支持持续监控,不错过瞬时高峰
适用场景: 适合在生产环境快速救场,尤其是CPU飙高持续时间较短的场景。放在服务器上常备,关键时刻能救命。
📊 工具2:fastthread.io - 在线分析专家
为什么推荐它?
如果说show-busy-java-threads.sh是"急救箱",那fastthread.io就是"体检中心"。
它是一个在线的线程栈分析工具,可以把jstack dump出的线程栈文件上传上去,生成一份详细的可视化报告。不仅能看CPU,还能发现死锁、线程泄漏、阻塞等问题。
什么时候用它?
当你已经用jstack dump了线程栈,但是:
- 线程太多(几千个),肉眼根本看不过来
- 想分析线程的整体状态分布
- 怀疑有死锁或者阻塞
- 想生成报告给其他人看
我一般会这样用:
- 先用show-busy-java-threads.sh快速定位
- 如果问题不明显,再用jstack dump完整线程栈
- 扔到fastthread.io深度分析
使用步骤
1. 生成线程栈文件:
bash
# 获取Java进程ID
jps -l
# dump线程栈(带锁信息)
jstack -l <pid> > thread_dump.txt
2. 访问fastthread.io并上传:
打开 fastthread.io/,把`thread_d...
3. 查看分析报告:
报告包含这些内容:
① 线程总览:
yaml
Total Threads: 156
Runnable: 8
Waiting: 120
Timed_Waiting: 25
Blocked: 3
② CPU热点线程: 自动识别出占用CPU最高的线程,按百分比排序。
③ 线程分组统计: 按线程名前缀分组,比如:
makefile
http-nio-8080-exec: 50 threads
scheduling-: 10 threads
能快速看出哪个线程池的线程最多。
④ 死锁检测: 如果有死锁,会高亮显示并画出依赖关系图。
⑤ 阻塞分析: 统计哪些线程在等待同一把锁,帮你发现锁竞争问题。
实战技巧
技巧1:多次dump对比
CPU飙高时,连续dump 3次线程栈(间隔1秒),分别上传到fastthread.io。如果某个方法在3次dump中都出现,基本可以确定就是它了。
bash
jstack <pid> > dump1.txt
sleep 1
jstack <pid> > dump2.txt
sleep 1
jstack <pid> > dump3.txt
技巧2:关注RUNNABLE状态
CPU高的时候,重点看状态是RUNNABLE
的线程。WAITING
和TIMED_WAITING
的线程不占CPU。
优势:
- ✅ 可视化报告,一目了然
- ✅ 自动检测死锁、阻塞等问题
- ✅ 无需安装,浏览器就能用
- ✅ 支持多次dump对比分析
适用场景: 适合事后分析、深度排查、生成报告给团队共享。对于复杂的线程问题(死锁、线程泄漏),效果特别好。
🔧 工具3:Arthas - 阿里开源的诊断神器
为什么推荐它?
Arthas是阿里开源的Java诊断工具,功能非常强大,堪称"瑞士军刀"。不仅能定位CPU问题,还能:
- 反编译线上代码
- 实时修改日志级别
- 查看方法调用耗时
- 查看类加载信息
- ...
我在之前的文章《线程暴增20K+!一次惊心动魄的Jenkins性能排查之旅》里,就是用Arthas的classloader
命令找到了问题的根源。
对于CPU问题,Arthas的thread
命令特别好用。
使用方法
1. 安装并启动:
bash
# 下载arthas-boot.jar
curl -O https://arthas.aliyun.com/arthas-boot.jar
# 启动并attach到Java进程
java -jar arthas-boot.jar
启动后会列出当前所有Java进程,输入序号选择要诊断的进程:
less
[INFO] arthas-boot version: 3.7.1
[INFO] Found existing java process, please choose one and input the serial number.
* [1]: 12345 com.company.Application
[2]: 23456 org.elasticsearch.bootstrap.Elasticsearch
1
2. 查看CPU占用最高的线程:
bash
# 显示CPU占用最高的3个线程
thread -n 3
输出示例:
scss
"http-nio-8080-exec-123" Id=156 RUNNABLE (in native)
at sun.nio.ch.EPollArrayWrapper.epollWait(Native Method)
at sun.nio.ch.EPollArrayWrapper.poll(EPollArrayWrapper.java:269)
at sun.nio.ch.EPollSelectorImpl.doSelect(EPollSelectorImpl.java:93)
...
"background-task-2" Id=89 RUNNABLE
at com.company.service.DataProcessor.process(DataProcessor.java:234)
at com.company.service.DataProcessor.run(DataProcessor.java:156)
at java.lang.Thread.run(Thread.java:748)
CPU占用: 45.3%
3. 持续监控某个线程:
bash
# 查看指定线程ID的详细信息
thread 156
# 每3秒刷新一次
thread -i 3000
4. 查看所有线程的状态分布:
bash
thread
会输出:
yaml
Threads Total: 156, NEW: 0, RUNNABLE: 8, BLOCKED: 3, WAITING: 120, TIMED_WAITING: 25
ID NAME GROUP PRIORITY STATE %CPU TIME
89 background-task-2 main 5 RUNNABLE 45.3 0:23.567
156 http-nio-8080-exec-123 main 5 RUNNABLE 12.1 0:08.234
...
优势:
- ✅ 实时交互,无需重启应用
- ✅ 功能丰富,一个工具顶十个
- ✅ 不影响性能,可以在生产环境使用
- ✅ 社区活跃,文档齐全
适用场景: 适合复杂问题的深度诊断,尤其是需要实时交互、方法追踪的场景。是每个Java工程师都应该掌握的神器。
📋 三个工具对比总结
工具 | 上手难度 | 速度 | 功能丰富度 | 使用场景 |
---|---|---|---|---|
show-busy-java-threads.sh | ⭐ 极简 | ⚡️ 秒级 | ⭐⭐ 单一 | 生产环境快速救场 |
fastthread.io | ⭐⭐ 简单 | ⚡️⚡️ 分钟级 | ⭐⭐⭐ 中等 | 事后深度分析、生成报告 |
Arthas | ⭐⭐⭐ 需学习 | ⚡️ 实时 | ⭐⭐⭐⭐⭐ 最强 | 复杂问题诊断、实时监控 |
我的推荐:
- 新手:先学show-busy-java-threads.sh,一行命令搞定90%的场景
- 进阶:学会fastthread.io,应对复杂的线程问题
- 老手:必须掌握Arthas,这是Java工程师的核心竞争力
组合使用效果最佳:
- 问题发生时,先用
show-busy-java-threads.sh
快速定位 - 如果一次看不出问题,dump完整线程栈扔到
fastthread.io
分析 - 需要深度排查时,用
Arthas
的thread
、trace
、watch
等命令追踪方法
💡 最后的建议
1. 别等出问题再学工具
很多人都是这样:线上出问题了,才开始Google"怎么定位CPU高",然后手忙脚乱。
正确做法:
- 在测试环境提前把这三个工具装好、玩熟
- 写个死循环程序,模拟CPU飙高,练习定位
- 把常用命令整理成checklist,贴在工位上
关键时刻,肌肉记忆能救命。
2. 监控告警要先行
工具再好,也只是"事后诸葛亮"。更重要的是提前发现问题:
- 配置CPU使用率告警(建议阈值70%)
- 配置JVM线程数告警
- 配置接口响应时间告警
发现得越早,处理越从容。
3. 养成记录习惯
每次排查完问题,记得写个复盘文档:
- 问题现象
- 定位过程
- 根本原因
- 解决方案
不是为了写而写,是为了下次遇到类似问题,能快速找到解决思路。
📮 我是稳哥,深耕Java和中间件领域多年,专注分享实战经验和技术干货。
💡 关注我,一起探索:
- 🔧 线上问题排查实战
- ⚡ 性能优化真实案例
- 🎯 架构设计最佳实践
- 🚀 从原理到实战的技术深度剖析
关注公众号【稳哥的随笔】,让我们一起在技术的道路上不断精进! 🚀
如果这篇文章对你有帮助,欢迎点赞、收藏、转发,你的支持是我创作的最大动力!