####简介
在线上环境中有时会遇到cpu等资源占用过多的资源我们可以使用top命令和jstack命令对问题进行排查
编写循环代码
下面代码开启两个线程循环打印
1 | public class Test { |
将代码发布到linux上并执行
开启jar应用
1 | nohup java -jar test.jar >/dev/null 2>&1 & |
使用top命令查看进程情况
我们可以从命令中看到pid 19384占用了大量资源
1 | top |
使用top命令查看线程情况
从上一步我们得到进程pid,现在我们使用top命令查看进程pid下的线程
1 | top -Hp 19384 |
我们可以看到19436 和19437这两个线程占用了大量资源
使用jstack命令进行具体分析
根据进程pid进行查询
1 | jstack -l 19437 |
我们由上面的top线程查询到19436和19437这两个线程占用了大量资源
将其转化成16进制分别为4bec和4bed
根据16进制的pid查询对应的nid,如图我们找到了pool-1-thread-2 这个线程名对应的nid为4bed,这个线程就是我们之前开启的一个线程,我们可以查看之中的堆栈信息发现其在runTest方法中持续执行,并且持续在执行io流(打印)
通过thread dump分析线程状态
除了上述的分析,大多数情况下会基于thead dump分析当前各个线程的运行情况,如是否存在死锁、是否存在一个线程长时间持有锁不放等等。在dump中,线程一般存在如下几种状态:
- RUNNABLE,线程处于执行中
- BLOCKED,线程被阻塞
- WAITING,线程正在等待
问题
在实际调试中这两个线程无法并发执行,始终都是一个线程为RUNNABLE,一个为BLOCKED,但是实际代码并未加锁,根据堆栈打印出的信息线程中是在io流中加了锁
1 | locked <0x0000000085c3d2e0> (a java.io.OutputStreamWriter) |
于是查看System.out.println(“ “)的源代码,可以看出源码中打印代码时加了锁的,所以导致两个线程无法并发
1 | public void println(String x) { |
系统资源监控命令
- vmstat
- iostat