线程堆栈也称作线程调用堆栈。Java线程堆栈是虚拟机中线程(包括锁)状态的一个瞬间快照,即系统在某个时刻所有线程的运行状态,包括每一个线程的调用堆栈,锁的持有情况等信息。
线程堆栈的信息都包含:
- 线程的名字,ID,线程的数量等。
- 线程的运行状态,锁的状态(锁被哪个线程持有,哪个线程再等待锁等)。
- 调用堆栈(即函数的调用层次关系)。调用堆栈包含完整的类名,所执行的方法,源代码的行数。
借助线程堆栈,可以分析许多问题,如线程死锁、锁争用、死循环、识别耗时操作等等。在多线程场合下的稳定性问题分析和性能问题分析,线程堆栈分析是最有效的方法,在多数情况下甚至无需对系统了解就可以进行相应的分析。
线程堆栈最善于分析如下类型的问题:
• 系统无缘无故CPU过高。
• 系统挂起,无响应。
• 系统运行越来越慢。
• 性能瓶颈(如无法充分利用CPU等)
• 线程死锁、死循环,饿死等。
• 由于线程数量太多导致系统失败(如无法创建线程等)。
输出线程状态
Java虚拟机提供了线程转储(Thread dump)的后门,通过这个后门,可以将线程堆栈打印出来。
我们这里拿Linux做例子,写了一个简单的java程序在Linux一直运行着:
- kill -3 [java pid]
不会在当前终端输出,它会输出到代码执行的或指定的地方去。比如,kill -3 tomcat pid, 输出堆栈到log目录下。 - Jstack [java pid]
这个比较简单,在当前终端显示,也可以重定向到指定文件中。 - JvisualVM:Thread Dump
不做说明,打开JvisualVM后,都是界面操作,过程还是很简单的。
解读线程状态
dump的线程信息
1 | "main" prio=10 tid=0x00007f730c008800 nid=0x63eb runnable [0x00007f73117c6000] |
线程堆栈里面的最直观的信息是当前线程的调用上下文,即从哪个函数中调用到哪个函数中(从下往上看),正执行到哪个类的哪一行.
解读
“main” prio=10 tid=0x00007f730c008800 nid=0x63eb runnable [0x00007f73117c6000]
“main” - 线程名称
prio=10 - 线程优先级
tid=0x00007f730c008800 - 线程ID
nid=0x63eb - 对应本地线程ID
runnable - 线程状态
[0x00007f73117c6000] - 线程占用内存地址“本地线程”是指该Java线程所对应的虚拟机中的本地线程。
- ps –ef|grep java:获取java进程id
- 使用pstack
获得Java虚拟机的本地线程的堆栈
- at test.fun2 (test.java:19)
test - 类名
fun2 - 方法名
test.java - 源代码文件
19 - 所在行号
瓶颈分析
详细参考文章:分析