转载:http://www.jianshu.com/p/6690f7e92f27,作了部分修改java
记得前段时间,同事说他们测试环境的服务器cpu使用率一直处于100%,本地又没有什么接口调用,为何会这样?cpu使用率居高不下,天然是有某些线程一直占用着cpu资源,那又如何查看占用cpu较高的线程?linux
固然一个正常的程序员不会写出上述代码,这里只是为了让一个线程占用较高的cpu资源(while循环执行逻辑会一直占用线程致使接近100%的cpu占用(若是是wait()挂起线程则不会),若是是多核如4核则一个应用程序cpu占用达到400%也是可能的)。程序员
在linux环境下,能够经过top
命令查看各个进程的cpu使用状况,默认按cpu使用率排序服务器
一、上图中能够看出pid为23344的java进程占用了较多的cpu资源;
二、经过top -Hp 23344
能够查看该进程下各个线程的cpu使用状况;多线程
(注意, top -Hp 23344后显示以下图,这里的PID则不是进程id了而是进程23344的各个线程id)ide
上图中能够看出pid为25077的线程占了较多的cpu资源,利用jstack命令能够继续查看该线程当前的堆栈状态(jstack是经过查看进程详情来查看进程里线程的状态)。测试
经过top命令定位到cpu占用率较高的线程以后,继续使用jstack pid(进程id)
命令查看当前java进程的堆栈状态spa
(上面的nid就是线程id,不过它是十六进制的;最前面""括起来的是线程名;由下往上看打印信息才是时间顺序)线程
jstack命令生成的thread dump信息包含了JVM中全部存活的线程,为了分析指定线程,必须找出对应线程的调用栈,应该如何找?code
在top命令中,已经获取到了占用cpu资源较高的线程pid,将该pid转成16进制的值,在thread dump中每一个线程都有一个nid,找到对应的nid便可;隔段时间再执行一次stack命令获取thread dump,区分两份dump是否有差异,在nid=0x246c的线程调用栈中,发现该线程一直在执行JstackCase类的内部类Task第33行的calculate方法,获得这个信息,就能够检查对应的代码是否有问题。
除了上述的分析,大多数状况下会基于thead dump分析当前各个线程的运行状况,如是否存在死锁、是否存在一个线程长时间持有锁不放等等。
在dump中,线程通常存在以下几种状态:
一、RUNNABLE,线程处于执行中
二、BLOCKED,线程被阻塞
三、WAITING,线程正在等待
4. TIMED_WAITING,这个通常是指这个线程是Timer按期执行任务,可是当前处于waiting状态
很明显:线程1获取到锁,处于RUNNABLE状态,线程2处于BLOCK状态
一、locked <0x000000076bf62208>
说明线程1对地址为0x000000076bf62208对象进行了加锁;
二、waiting to lock <0x000000076bf62208>
说明线程2在等待地址为0x000000076bf62208对象上的锁;
三、waiting for monitor entry [0x000000001e21f000]
说明线程2是经过synchronized关键字进入了监视器的临界区等待,并处于"Entry Set"队列,等待monitor,具体实现能够参考深刻分析synchronized的JVM实现;
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都处于WAITING状态
一、线程1和2都是先locked <0x000000076bf62500>
,再waiting on <0x000000076bf62500>
,之因此先锁再等同一个对象,是由于wait方法须要先经过synchronized得到该地址对象的monitor;
二、waiting on <0x000000076bf62500>
说明线程执行了wait方法以后,释放了monitor,进入到"Wait Set"队列,等待其它线程执行地址为0x000000076bf62500对象的notify方法,并唤醒本身,具体实现能够参考深刻分析Object.wait/notify实现机制;