一、命令介绍
jstack是jdk自带的jvm分析工具,用于打印指定 java进程,core文件 或者远程 调试服务 的java线程栈信息,从而分析java程序性能不佳或者崩溃的问题。另外该命令是实验性的,不被支持。
jstack命令非常简单,使用自描述的帮助文档,可以快速掌握其使用方法:
jstack -help
Usage:
jstack [-l]
(to connect to running process)
jstack -F [-m] [-l]
(to connect to a hung process)
jstack [-m] [-l]
(to connect to a core file)
jstack [-m] [-l] [server_id@]
(to connect to a remote debug server)
Options:
-F to force a thread dump. Use when jstack does not respond (process is hung)
-m to print both java and native frames (mixed mode)
-l long listing. Prints additional information about locks
-h or -help to print this help message
如上,jstack命令作用的对象有三种,不同对象命令格式如下:
进程: 使用jstack [-l] 来连接到正在运行的进程,使用 jstack -F [-m] [-l] 来连接到挂起的进程。
core/executable: core文件是Linux下程序不正常退出产生的文件;executable文件是可产生core dump文件的java可执行程序;使用jstack [-m] [-l] 命令。
远程服务: jstack [-m] [-l] [server_id@]连接远程服务。
snapshoot 快照
一个活跃的java程序,其虚拟机内的线程也是活跃的,不断新建销毁,在各个线程状态之间转移。jstack命令,其实是对命令执行时刻的虚拟机线程集合做一个快照,包含了当前时刻虚拟机内所有线程方法栈。便于通过线程方法栈的行为,定位程序性能不佳或者崩溃问题。这些行为主要是线程之间的同步,如死锁,死循环,等待外部资源竞争锁的行为。通过分析离线文件或者附着到正在运行的java进程,定位问题。
一窥方法栈
一段线程方法栈信息如下:
"localhost-startStop-1-SendThread(10.0.24.14:2181)" daemon prio=10 tid=0x00002b0ee8b4e000 nid=0x4b37 waiting for monitor entry [0x00002b0ed5162000]
java.lang.Thread.State: BLOCKED (on object monitor)
at org.apache.log4j.Category.callAppenders(Category.java:204)
- waiting to lock <0x00000000db301138> (a org.apache.log4j.spi.RootLogger)
at org.apache.log4j.Category.forcedLog(Category.java:391)
at org.apache.log4j.Category.log(Category.java:856)
at org.slf4j.impl.Log4jLoggerAdapter.info(Log4jLoggerAdapter.java:305)
at org.apache.zookeeper.ClientCnxn$SendThread.run(ClientCnxn.java:1156)
跟普通的java方法调用栈很相似,但是又多了些额外的信息,下面重点介绍这些额外的信息。
二、线程状态
jstack打印出的线程状态与java线程状态很相似,但并不是严格意义上相同。
java线程的状态图大概如下:
java线程状态
NEW: 实例化Thread类后的线程对象,不可执行。
RUNNABLE: 调用线程的start()方法后;等待CPU时间片。
RUNNING: 获得CPU时间片,正在执行。
WAITING: 线程等待其他线程执行特定操作,等待时间不确定。
TIMED_WAITING: 线程等待其他线程执行特定操作,等待时间确定。
BLOCKED: 进入同步方法或者同步代码块,没有获取到锁,进入该状态。
TERMINATED: 线程执行完毕,或者抛出未处理的异常,线程结束。
实际上,Thread的内部枚举类 java.lang.Thread.State 也对java线程状态做了介绍,其中没有 RUNNING 状态,以上是考虑CPU调度引入的这个状态。
thread states
jstack导出的线程方法栈状态也是以java线程状态为准,不过,jvm中的实际线程状态不包括NEW以及TERMINATED,只包括:
RUNNABLE
WAITING
TIMED_WAITING
BLOCKED
Monitor机制
操作系统为支持进程/线程间的同步,提供了一些基本的同步原语,其中semaphore信号量 和 mutex互斥量是其中最重要的同步原语。但是使用基础同步原语控制并发时,程序员必须维护繁琐的细节,何时应该加锁,何时应该唤醒进程/线程;为便于开发并发程序,一些高级语言支持了Monitor机制,类似语法糖,操作系统本身不支持Monitor,其实现依赖基础同步原语。
具体到高级语言Java,synchronized ,Object(wait, notify/notif