在Java应用的性能测试中,很多性能问题可以通过观察线程堆栈来发现,Jstack是JVM自带dump线程堆栈的工具,很轻量易用,并且执行时不会对性能造成很大的影响。灵活的使用jstack可以发现很多隐秘的性能问题,是定位问题不可多得的好帮手。
1、线程堆栈
线程堆栈也称为线程调用堆栈。Java线程堆栈是虚拟机中线程(包括锁)状态的一个瞬间的快照,即系统在某个时刻所有线程的运行状态,包括每一个线程的调用堆栈,锁的持有情况等信息。从线程堆栈中可以得到以下信息
a.线程的名字,ID,线程的数量等
b.线程的运行状态,锁的状态(锁被哪个线程持有,哪个线程在等待锁等)
c.函数间的调用关系,包括完整类名,所执行的方法,源代码的行数等等
2、命令使用
jstack <pid> >filename : 获取应用运行时的线程堆栈
说明:pid为应用进程号
对于java应用而言,以下常见的几个性能问题都可以从线程堆栈入手定位
- 系统挂起无响应
- 系统cpu较高
- 系统运行的响应时间长
- 线程死锁等
3、线程的运行状态
常用到的几个线程状态有 RUNNABLE、BLOCKED、WAITING、TIMED_WAITING
RUNNABLE
RUNNABLE状态表示线程正处于运行状态。一般情况下处于运行状态线程是会消耗CPU的,但不是所有的RUNNABLE都会消耗CPU, 比如线程进行网络IO时,这时线程状态是挂起的,但由于挂起发生在本地代码,虚拟机并不感知,所以不会像显示调用Java的sleep()或者wait()等方法进入WAITING状态,只有等数据到来时才消耗一点CPU。
TIMED_WAITING/WAITING
这两种状态表示线程被挂起,等待被唤醒,当设置超时时间时状态为TIMED_WAITING,如果未设置超时时间,这时的状态为WAITING,必须等待lock.notify()或lock.notifyAll()或接收到interrrupt信号才能退出等待状态。
TIMED_WAITING/WAITING下还需要关注下面几个线程状态:
- waiting on condition : 说明线程等待另一个条件的发生,来把自己唤醒
- on object monitor :说明该线程正在执行obj.wait()方法,放弃了Monitor, 进入" Wait Set "队列
BLOCKED
此时的线程处于阻塞状态,一般是在等待进入一个人临界区 "waiting for monitor entry'",这种状态是需要重点关注的
4、哪些线程状态占用CPU
处于TIMED_WAITING、WATING、BLOCKED状态的线程是不消耗CPU的,而处于RUNNABLE状态的线程要结合当前代码的性质判断是否消耗CPU
- 纯java运算代码,并且未被挂起,是消耗CPU的
- 网络IO操作,在等待数据时是不消耗CPU的
参考地址
jstack性能问题定位案例分析详解 :https://blog.csdn.net/qq_30353203/article/details/76690272