背景
记得前段时间,同事说他们的测试环境中服务器的CPU使用率一直在100%,并且没有任何本地接口调用。 为什么会发生这种情况? CPU使用率依然居高不下。 自然就有一些线程一直在占用cpu资源,那么如何查看占用cpu高的线程呢?
当然,一个正常的程序员不会写上面的代码,这里只是为了让线程占用更高的cpu资源。
顶部命令
在Linux环境下,可以使用top命令查看各个进程的cpu使用情况。 默认情况下,它们按 cpu 使用情况排序。
1、从上图可以看出,pid为23344的java进程占用CPU资源较多;
2、通过top -Hp 23344可以查看进程下各个线程的CPU使用情况;
从上图可以看出,pid为25077的线程占用CPU资源较多,可以继续使用命令查看该线程当前的堆栈状态。
命令
通过top命令定位到CPU使用率较高的线程后,继续使用pid命令查看当前java进程的堆栈状态
该命令生成的转储信息包括 JVM 中所有存活的线程。 为了分析指定线程,必须找到对应线程的调用堆栈。 如何找到它?
top命令中已经获取了占用CPU资源较高的线程的pid,并将pid转换为16进制值。 dump中,每个线程都有一个nid,找到对应的nid即可; 执行一次stack命令获取dump,并区分两次dump是否不同。 在nid=的线程调用栈中,发现该线程一直在执行类的第33行的方法。 得到这些信息后,就可以检查对应的代码是否有问题。 。
通过dump分析线程状态
除了上面的分析之外,大多数情况下都会根据thead dump来分析各个线程的运行状态,比如是否存在死锁、是否有线程长时间持有锁等等。
在dump中,线程一般存在以下几种状态:
1、线程正在执行
2、线程被阻塞
3、线程正在等待
示例1:多线程竞争锁
显然:线程1获得锁并处于BLOCK状态,线程2处于BLOCK状态
1、说明线程1已经将该地址锁定为对象;
2. to lock 表示线程2正在等待地址为的对象的锁;
3.[]表示线程1通过关键字已经进入了监视器的临界区,在“”队列中,等待。 具体实现请参考JVM实现深入分析;
示例2:通过wait挂起线程
static class Task implements Runnable { @Override public void run() { synchronized (lock) { try { lock.wait(); //TimeUnit.SECONDS.sleep(100000); } catch (InterruptedException e) { e.printStackTrace(); } } } }
转储结果
线程1和线程2都处于状态
1. 线程 1 和 2 都先打开,然后再打开。 之所以先加锁,再等于对象,是因为wait方法需要先获取地址对象;
2、on表示线程执行完wait方法后被释放,进入“Wait Set”队列,等待其他线程执行地址为该对象的方法,并唤醒自身。