java占用线程高的排查方法
解压arthas
启动案例程序
bash
nohup java -jar math-game.jar > 1.txt 2>&1 &
展示当前最繁忙的 5 个线程,并按 CPU 占用率从高到低排序
bash
java -jar arthas-boot.jar
[arthas@6028]$ thread -n 5
"arthas-command-execute" Id=22 cpuUsage=0.25% deltaTime=0ms time=3ms RUNNABLE
at sun.management.ThreadImpl.dumpThreads0(Native Method)
at sun.management.ThreadImpl.getThreadInfo(ThreadImpl.java:448)
at com.taobao.arthas.core.command.monitor200.ThreadCommand.processTopBusyThreads(ThreadCommand.java:206)
at com.taobao.arthas.core.command.monitor200.ThreadCommand.process(ThreadCommand.java:122)
at com.taobao.arthas.core.shell.command.impl.AnnotatedCommandImpl.process(AnnotatedCommandImpl.java:82)
at com.taobao.arthas.core.shell.command.impl.AnnotatedCommandImpl.access$100(AnnotatedCommandImpl.java:18)
抓取火焰图10秒
bash
[arthas@6028]$ profiler start --duration 10
Profiling started
profiler will silent stop after 10 seconds.
profiler output file will be: /root/arthas-output/20260610-190020.html
# 抓10s火焰图并指定位置输出
[arthas@2527]$ profiler start -d 10 -f /root/hyt/myhyt10s.html
Profiling started
profiler will silent stop after 10 seconds.
profiler output file will be: /root/hyt/myhyt10s.html
手动抓火焰图
bash
[arthas@2527]$ profiler start
Profiling started
[arthas@2527]$ profiler status
Profiling is running for 6 seconds
[arthas@2527]$ profiler stop
OK
profiler output file: /root/art/arthas-output/20260613-165656.html
# 指定目录停止
profiler stop -f /root/hyt/myhyt.html
使用arthas保存当前的dump
bash
[arthas@2527]$ heapdump
Dumping heap to /tmp/heapdump2026-06-13-17-154000252027065352381.hprof ...
Heap dump file created
指定生成的目录
bash
[arthas@2527]$ heapdump /home/admin/dumps/myapp-2024.hprof
Dumping heap to /home/admin/dumps/myapp-2024.hprof ...
Heap dump file created
jmap 保存当时内存快照
bash
[root@localhost ~]# ps -ef | grep java
root 2527 1899 0 16:50 pts/0 00:00:05 java -jar math-game.jar
root 4923 4560 0 17:24 pts/1 00:00:00 grep --color=auto java
[root@localhost ~]# jmap -dump:format=b,file=/tmp/heap.hprof 2527
Dumping heap to /tmp/heap.hprof ...
Heap dump file created
jstack 打印指定java进程的堆栈
bash
# 打印线程堆栈(会输出所有线程)
jstack <pid>
# 打印锁信息(包括死锁检测)
jstack -l <pid>
# 如果进程无响应,强制打印(通常用于 -F 参数)
jstack -F <pid>
打印JVM 的堆栈信息,以供问题排查
bash
[root@localhost art]# ps -ef | grep java
root 2527 1899 0 16:50 pts/0 00:00:00 java -jar math-game.jar
root 2770 1899 0 16:52 pts/0 00:00:00 grep --color=auto java
[root@localhost.com ~]# jstack -F 2527 > /tmp/jstack1.log
[root@localhost.com ~]# jstack 2527 > /tmp/jstack2.log
Tomcat底层是通过JVM运行的,JVM在操作系统中是作为一个进程存在的,而java中的所有线程是在VM进程中运行的,同时cPU调度的是进程中的线程。那么,要查看java是否支持多线程,是体现在操作系统中的,我们可以查看java进程是否可以使用CPU的多核资源。如果可以,那么java就是支持多线程的,而支持多线程的话,java进程占用CPU资源300%以上是完全可能的。
使用jstack工具将进程信息打印输出
jstack是java虚拟机自带的一种堆栈跟踪工具。可以用于生成java虚拟机当前时刻的线程快照。线程快照是当前java虚拟机内每一条线程正在执行的方法堆栈的集合,生成线程快照的主要目的是定位线程出现长时间停顿的原因,如线程间死锁、死循环、请求外部资源导致的长时间等待等。
想要通过jstack命令来分析线程的情况的话,首先要知道线程都有哪些状态,下面这些状态是我们使用istack命令查看线程堆栈信息时可能会看到的线程的几种状态
NEW,未启动的。不会出现在Dump中
RUNNABLE,在虚拟机内执行的运行中状态。
BLOCKED,受阻塞并等待监视器锁WATiNG,无限期等待另一个线程执行特定操作
TIMED_WATING,有时限的等待另一个线程的特定操作
TERMINATED,已退出的
案例分析
bash
top
top -H -p 3994
printf '%x\n' 3995
jstack 3994 | grep f9b
java进程的id 某线程的16进制
bash
[root@localhost ~]# top
top - 20:25:36 up 1:10, 3 users, load average: 0.00, 0.01, 0.03
Tasks: 202 total, 2 running, 200 sleeping, 0 stopped, 0 zombie
%Cpu(s): 0.2 us, 0.2 sy, 0.0 ni, 99.5 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st
KiB Mem : 4026160 total, 2875184 free, 700224 used, 450752 buff/cache
KiB Swap: 4063228 total, 4063228 free, 0 used. 3083524 avail Mem
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
3994 root 20 0 4210704 122736 14308 S 1.0 3.0 0:06.26 java
1 root 20 0 191276 4216 2604 S 0.0 0.1 0:03.12 systemd
2 root 20 0 0 0 0 S 0.0 0.0 0:00.01 kthreadd
4 root 0 -20 0 0 0 S 0.0 0.0 0:00.00 kworker/0:0H
6 root 20 0 0 0 0 S 0.0 0.0 0:00.06 ksoftirqd/0
7 root rt 0 0 0 0 S 0.0 0.0 0:00.11 migration/0
8 root 20 0 0 0 0 S 0.0 0.0 0:00.00 rcu_bh
9 root 20 0 0 0 0 S 0.0 0.0 0:00.76 rcu_sched
10 root 0 -20 0 0 0 S 0.0 0.0 0:00.00 lru-add-drain
11 root rt 0 0 0 0 S 0.0 0.0 0:00.02 watchdog/0
12 root rt 0 0 0 0 S 0.0 0.0 0:00.01 watchdog/1
13 root rt 0 0 0 0 S 0.0 0.0 0:00.10 migration/1
[root@localhost ~]# top -H -p 3994
top - 20:25:42 up 1:10, 3 users, load average: 0.00, 0.01, 0.03
Threads: 25 total, 0 running, 25 sleeping, 0 stopped, 0 zombie
%Cpu(s): 0.0 us, 0.0 sy, 0.0 ni,100.0 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st
KiB Mem : 4026160 total, 2875804 free, 699604 used, 450752 buff/cache
KiB Swap: 4063228 total, 4063228 free, 0 used. 3084144 avail Mem
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
3994 root 20 0 4210704 122736 14308 S 0.0 3.0 0:00.02 java
3995 root 20 0 4210704 122736 14308 S 0.0 3.0 0:00.51 java
3996 root 20 0 4210704 122736 14308 S 0.0 3.0 0:00.32 java
3997 root 20 0 4210704 122736 14308 S 0.0 3.0 0:00.31 java
3998 root 20 0 4210704 122736 14308 S 0.0 3.0 0:00.30 java
3999 root 20 0 4210704 122736 14308 S 0.0 3.0 0:00.32 java
4000 root 20 0 4210704 122736 14308 S 0.0 3.0 0:00.14 java
4001 root 20 0 4210704 122736 14308 S 0.0 3.0 0:00.00 java
4002 root 20 0 4210704 122736 14308 S 0.0 3.0 0:00.00 java
4003 root 20 0 4210704 122736 14308 S 0.0 3.0 0:00.00 java
4004 root 20 0 4210704 122736 14308 S 0.0 3.0 0:00.29 java
4005 root 20 0 4210704 122736 14308 S 0.0 3.0 0:00.26 java
[root@localhost ~]# printf '%x\n' 3995
f9b
[root@localhost ~]# jstack 3994 | grep f9b
"main" #1 prio=5 os_prio=0 tid=0x00007fd340008800 nid=0xf9b waiting on condition [0x00007fd346105000]
匹配该行及之后50行 -B是before 之前的50行
[root@localhost ~]# jstack 3994 | grep f9b -A 50
"main" #1 prio=5 os_prio=0 tid=0x00007fd340008800 nid=0xf9b waiting on condition [0x00007fd346105000]
java.lang.Thread.State: TIMED_WAITING (sleeping)
at java.lang.Thread.sleep(Native Method)
at java.lang.Thread.sleep(Thread.java:340)
at java.util.concurrent.TimeUnit.sleep(TimeUnit.java:386)
at demo.MathGame.main(MathGame.java:17)
"VM Thread" os_prio=0 tid=0x00007fd34013d800 nid=0xfa0 runnable
"GC task thread#0 (ParallelGC)" os_prio=0 tid=0x00007fd34001d800 nid=0xf9c runnable
"GC task thread#1 (ParallelGC)" os_prio=0 tid=0x00007fd34001f800 nid=0xf9d runnable
"GC task thread#2 (ParallelGC)" os_prio=0 tid=0x00007fd340021800 nid=0xf9e runnable
"GC task thread#3 (ParallelGC)" os_prio=0 tid=0x00007fd340023000 nid=0xf9f runnable
"VM Periodic Task Thread" os_prio=0 tid=0x00007fd3401bb800 nid=0xfa8 waiting on condition
JNI global references: 283