1 jstack
jstack是JDK自带的一种线程栈跟踪工具,用于生成java虚拟机当前时刻线程快照。在定位线程卡顿、死锁、block等原因的时候非常有用。使用方法是:
jstack [-l] pid
2 Monitor
Monitor是java中用以实现线程同步和互斥的主要手段,每一个对象有且只有一个monitor,可以理解monitor就是一个对象锁。用下面这张著名的图来描述线程和monitor的关系
- Entry Set中的线程正在通过synchronized要求获取到对象锁。如果获取到锁就会进度The Owner,没有获取到锁就会在Entry Set等待
- The Owner中的线程成功竞争到锁
- Wait Set表示线程调用wait方法,释放对象锁,并在Wait Set等待。当调用notify或者notifyAll后,处在Wait Set中的一个(notify)或者多个(notifyAll)线程就会被放到Entry Set中同其他没有获取到锁的线程一起竞争锁。
其实调用wait方法可以分为三个操作:
- 释放锁并阻塞(放到monitor的Wati Set中)
- 等待条件发生(时间到或者调用了notify或者notifyAll)
- 获取通知后,竞争获取锁(放到Entry Set中)
那么对于Jstack打印的线程栈来讲,处在EntrySet中的线程动作是"Waiting for monitor entry", 处在The Owner中的线程动作是“runnable”,处在Wait Set中的线程动作是“in Object.wait()”。
3 线程栈内容
网上有很多介绍jstack中线程状态的,但是讲解的比较乱,这里做下总结。
不同的jvm可能打印出的线程栈是不同的,当前使用的java版本如下
java version "1.8.0_111"
Java(TM) SE Runtime Environment (build 1.8.0_111-b14)
Java HotSpot(TM) 64-Bit Server VM (build 25.111-b14, mixed mode)
如下jstack打印出的线程栈快照
3.1 线程动作
线程动作在jstack中第一行,表示线程在做什么,个人理解起到概括的作用(网上很多把这块也当做线程状态,我觉得不太合适),之后才是真正的栈
- runnable 正在运行
- in Object.wait() 如上面介绍的,调用了wait方法,在Wait Set中
- waiting for monitor entry, 在Entry Set,等待获取锁
- waiting on condition 在等待某个状态的发生,如sleep,时间到后就会活跃,或者io阻塞
3.2 线程状态
第二行才是真正的线程状态,线程状态是在java.lang.Thread.State中已经定义了的(java.lang.Thread.State是个枚举类),我们可以看下java源码
public enum State {
/**
* Thread state for a thread which has not yet started.
*/
NEW,
/**
* Thread state for a runnable thread. A thread in the runnable
* state is executing in the Java virtual machine but it may
* be waiting for other resources from the operating system
* such as processor.
*/
RUNNABLE,
/**
* Thread state for a thread blocked waiting for a monitor lock.
* A thread in the blocked state is waiting for a monitor lock
* to enter a synchronized block/method or
* reenter a synchronized block/method after calling
* {@link Object#wait() Object.wait}.
*/
BLOCKED,
/**
* Thread state for a waiting thread.
* A thread is in the waiting state due to calling one of the
* following methods:
* <ul>
* <li>{@link Object#wait() Object.wait} with no timeout</li>
* <li>{@link #join() Thread.join} with no timeout</li>
* <li>{@link LockSupport#park() LockSupport.park}</li>
* </ul>
*
* <p>A thread in the waiting state is waiting for another thread to
* perform a particular action.
*
* For example, a thread that has called <tt>Object.wait()</tt>
* on an object is waiting for another thread to call
* <tt>Object.notify()</tt> or <tt>Object.notifyAll()</tt> on
* that object. A thread that has called <tt>Thread.join()</tt>
* is waiting for a specified thread to terminate.
*/
WAITING,
/**
* Thread state for a waiting thread with a specified waiting time.
* A thread is in the timed waiting state due to calling one of
* the following methods with a specified positive waiting time:
* <ul>
* <li>{@link #sleep Thread.sleep}</li>
* <li>{@link Object#wait(long) Object.wait} with timeout</li>
* <li>{@link #join(long) Thread.join} with timeout</li>
* <li>{@link LockSupport#parkNanos LockSupport.parkNanos}</li>
* <li>{@link LockSupport#parkUntil LockSupport.parkUntil}</li>
* </ul>
*/
TIMED_WAITING,
/**
* Thread state for a terminated thread.
* The thread has completed execution.
*/
TERMINATED;
}
可以看到java的线程状态一共是6种,分别是:NEW、RUNNABLE、BLOCKED、WAITING、TIMED_WAITING、TERMINATED
- BLOCKED 线程在等待获取锁,可以理解为在Entry Set中
- WAITING 由于调用了以下方法线程会变为WAITING状态:wait join park
- TIMED_WAITING 由于调用了以下放啊发线程会变为TIMED_WAITING:sleep wait(long) join(long)
3.3 调用修饰
- locked <地址> 获取到对象锁,monitor的y拥有者
- wating to lock <地址> 在Entry Set等待获取锁
- waiting on <地址> 获取到锁对象后,释放锁在Wait Set等待
- parking to wait for <地址>
3.4 其他
- prio 线程优先级
- tid 表示线程id
- nid 操作系统映射的线程id
- [0x0000700004843000] 表示线程栈的其实地址或者锁地址
4 参考
http://www.cnblogs.com/kongzhongqijing/articles/3630264.html