背景
对于系统运行越来卡顿,响应越来越慢的问题,绝大多数情况是程序本身问题造成的,掌握相关问题的排查和定位尤其重要。
现象
使用top命名查看目前服务所占cpu情况:
通过信息,可以看到有个进程占用CPU过高,接下来排查系统代码中哪些逻辑导致CPU过高。
步骤
第一步:通过ps命令查看这个程序的线程信息。
执行命令:ps -mp 27291-o THREAD,tid,time
属性介绍:tid代码线程ID,time代表这个线程的已运行时间,27291为对应pid的值。
如图可以看到这个进程中有1个线程的CPU占用率很高,达到了98.5%,并且它们目前也运行了44分钟了,对应TID为:27909
第二步:将TID(代码线程ID)转为16进制
因为jvm运行信息都是16进制,所以,这里需要将十进制转为16进制。
执行命令: printf"%x\n" 27909
第三步:jstack查看进程信息
执行命令:jstack27291 | grep 6d05 -A 30
内容介绍:27291 为pid进程,6d05 为需要查看的线程tid
输出信息有较为明显的的代码信息。
根据上面输出信息可以很快定位到本地代码存在的问题。
补充:
线程的Thread状态(java.lang.Thread.State)内容说明:
一个Thread对象可以有多个状态,在java.lang.Thread.State中,总共定义六种状态:
1、NEW
线程刚刚被创建,也就是已经new过了,但是还没有调用start()方法,jstack命令不会列出处于此状态的线程信息
2、RUNNABLE
RUNNABLE这个名字很具有欺骗性,很容易让人误以为处于这个状态的线程正在运行。事实上,这个状态只是表示,线程是可运行的。我们已经无数次提到过,一个单核CPU在同一时刻,只能运行一个线程。
3、BLOCKED
线程处于阻塞状态,正在等待一个monitor lock。通常情况下,是因为本线程与其他线程公用了一个锁。其他在线程正在使用这个锁进入某个synchronized同步方法块或者方法,而本线程进入这个同步代码块也需要这个锁,最终导致本线程处于阻塞状态。
4、WAITING
等待状态,调用以下方法可能会导致一个线程处于等待状态:
例如:对于wait()方法,一个线程处于等待状态,通常是在等待其他线程完成某个操作。本线程调用某个对象的wait()方法,其他线程处于完成之后,调用同一个对象的notify或者notifyAll()方法。Object.wait()方法只能够在同步代码块中调用。调用了wait()方法后,会释放锁。
5、TIMED_WAITING
线程等待指定的时间,对于以下方法的调用,可能会导致线程处于这个状态:
Thread.sleep #java.lang.Thread.State: TIMED_WAITING (sleeping)
Object.wait 指定超时时间 #java.lang.Thread.State: TIMED_WAITING (on object monitor)
Thread.join with timeout
LockSupport.parkNanos #java.lang.Thread.State: TIMED_WAITING (parking)
LockSupport.parkUntil #java.lang.Thread.State: TIMED_WAITING (parking)
6、TERMINATED
线程终止。
以上为全部内容。