jstack是java虚拟机自带的一种堆栈跟踪工具。jstack位于java的bin目录下,主要利用JVM内建的指令对Java应用程序的资源和性能进行实时的命令行的监控,包括了对Heap
size和垃圾回收状况的监控。
Jstat可以用来监视VM内存内的各种堆和非堆的大小及其内存使用量。
1、Jstack命令格式
jstack [ option ] pid
2、常用参数
-F当’jstack [-l] pid’没有相应的时候强制打印栈信息
-l长列表. 打印关于锁的附加信息,例如属于java.util.concurrent的ownable synchronizers列表.
-m打印java和native c/c++框架的所有栈信息.
-h | -help打印帮助信息
pid 需要被打印配置信息的java进程id,可以用jps查询.
3、生成死锁(deadlock)的源代码
package com.jdkTools;
/**
* 简单的应用,供测试JDK自带的jstack使用 本应用会造成deadlock,可能会导致系统崩溃
* 逻辑:一旦两个线程互相等待的局面出现,死锁(deadlock)就发生了
*
* @author 范芳铭
*/
public class EasyJstack extends Thread {
private EasyJstackResourceresourceManger;//资源管理类的私有引用,通过此引用可以通过其相关接口对资源进行读写
private int a, b;// 将要写入资源的数据
public static void main(String[]args) throws Exception {
EasyJstackResourceresourceManager = new EasyJstackResource();
EasyJstack stack1 = newEasyJstack(resourceManager, 1, 2);
EasyJstack stack2 = newEasyJstack(resourceManager, 3, 4);
stack1.start();
stack2.start();
}
publicEasyJstack(EasyJstackResource resourceManager, int a, int b) {
this.resourceManger =resourceManager;
this.a = a;
this.b = b;
}
public void run() {
while (true) {
this.resourceManger.read();
this.resourceManger.write(this.a,this.b);
}
}
}
package com.jdkTools;
/**
* 简单的应用,供测试JDK自带的jstack使用 本应用会造成deadlock,可能会导致系统崩溃
* 逻辑:一旦两个线程互相等待的局面出现,死锁(deadlock)就发生了
* @author 范芳铭
*/
public class EasyJstackResource {
/**
* 管理的两个资源,如果有多个线程并发,那么就会死锁
*/
private Resource resourceA = newResource();
private Resource resourceB = newResource();
public EasyJstackResource() {
this.resourceA.setValue(0);
this.resourceB.setValue(0);
}
public int read() {
synchronized (this.resourceA){
System.out.println(Thread.currentThread().getName()
+ "线程拿到了资源 resourceA的对象锁");
synchronized (resourceB){
System.out.println(Thread.currentThread().getName()
+ "线程拿到了资源 resourceB的对象锁");
return this.resourceA.getValue()+ this.resourceB.getValue();
}
}
}
public void write(int a, int b) {
synchronized (this.resourceB){
System.out.println(Thread.currentThread().getName()
+ "线程拿到了资源 resourceB的对象锁");
synchronized(this.resourceA) {
System.out.println(Thread.currentThread().getName()
+ "线程拿到了资源 resourceA的对象锁");
this.resourceA.setValue(a);
this.resourceB.setValue(b);
}
}
}
public class Resource {
private int value;// 资源的属性
public int getValue() {
return value;
}
public void setValue(intvalue) {
this.value = value;
}
}
}
4、运行结果
Thread-0线程拿到了资源 resourceA 的对象锁
Thread-0线程拿到了资源 resourceB 的对象锁
Thread-0线程拿到了资源 resourceB 的对象锁
Thread-1线程拿到了资源 resourceA 的对象锁
应用已经被锁住了
5、用jstack进行分析
C:\Program Files\Java\jdk1.6.0_25\bin>jps -l
5204 com.jdkTools.EasyJstack
6268 sun.tools.jps.Jps
5412
C:\Program Files\Java\jdk1.6.0_25\bin>jstack 5204
2015-01-21 15:32:22
Full thread dump Java HotSpot(TM) Client VM (11.3-b02mixed mode):
…中间省略
"Signal Dispatcher" daemon prio=10tid=0x01a42000 nid=0x1a5c runnable [0x00000000..0x00000000]
java.lang.Thread.State: RUNNABLE
"Finalizer" daemon prio=8 tid=0x01a2b000nid=0x1798 in Object.wait() [0x0bc3f000..0x0bc3fa68]
java.lang.Thread.State: WAITING (on object monitor)
atjava.lang.Object.wait(Native Method)
- waitingon <0x03b50b38> (a java.lang.ref.ReferenceQueue$Lock)
atjava.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:116)
- locked<0x03b50b38> (a java.lang.ref.ReferenceQueue$Lock)
atjava.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:132)
atjava.lang.ref.Finalizer$FinalizerThread.run(Finalizer.java:159)
"Reference Handler" daemon prio=10tid=0x01a29c00 nid=0x1e38 in Object.wait() [0x0bbef000..0x0bbefae8]
java.lang.Thread.State: WAITING (on object monitor)
atjava.lang.Object.wait(Native Method)
- waitingon <0x03b50a40> (a java.lang.ref.Reference$Lock)
atjava.lang.Object.wait(Object.java:485)
atjava.lang.ref.Reference$ReferenceHandler.run(Reference.java:116)
- locked<0x03b50a40> (a java.lang.ref.Reference$Lock)
"VM Thread" prio=10 tid=0x01a26800 nid=0x1cecrunnable
"VM Periodic Task Thread" prio=10tid=0x01a80000 nid=0x10e0 waiting on condition
JNI global references: 594
Found one Java-level deadlock:
=============================
"Thread-1":
waiting to lockmonitor 0x01a2dea4 (object 0x03b8ed40, acom.jdkTools.EasyJstackResource$Resource),
which is held by"Thread-0"
"Thread-0":
waiting to lockmonitor 0x01a2eb3c (object 0x03b8ed30, acom.jdkTools.EasyJstackResource$Resource),
which is held by"Thread-1"
Java stack information for the threads listed above:
===================================================
"Thread-1":
atcom.jdkTools.EasyJstackResource.read(EasyJstackResource.java:27)
- waitingto lock <0x03b8ed40> (a com.jdkTools.EasyJstackResource$Resource)
- locked<0x03b8ed30> (a com.jdkTools.EasyJstackResource$Resource)
atcom.jdkTools.EasyJstack.run(EasyJstack.java:34)
"Thread-0":
atcom.jdkTools.EasyJstackResource.write(EasyJstackResource.java:42)
- waitingto lock <0x03b8ed30> (a com.jdkTools.EasyJstackResource$Resource)
- locked<0x03b8ed40> (a com.jdkTools.EasyJstackResource$Resource)
atcom.jdkTools.EasyJstack.run(EasyJstack.java:35)
Found 1 deadlock.
能够明确看到“Found one Java-level deadlock:”能够找到系统中的死锁。
6、分析结果
Java stack information for the threads listed above:
===================================================
"Thread-1":
atcom.jdkTools.EasyJstackResource.read(EasyJstackResource.java:27)
- waitingto lock <0x03b8ed40> (a com.jdkTools.EasyJstackResource$Resource)
- locked<0x03b8ed30> (a com.jdkTools.EasyJstackResource$Resource)
atcom.jdkTools.EasyJstack.run(EasyJstack.java:34)
"Thread-0":
atcom.jdkTools.EasyJstackResource.write(EasyJstackResource.java:42)
- waitingto lock <0x03b8ed30> (a com.jdkTools.EasyJstackResource$Resource)
- locked<0x03b8ed40> (a com.jdkTools.EasyJstackResource$Resource)
atcom.jdkTools.EasyJstack.run(EasyJstack.java:35)
Found 1 deadlock.
仔细看这一段文字,告诉我们 EasyJstackResource.java:27出了状况。如果出现了这种情况,我们就要从这里开始顺藤摸瓜,解决问题。
7、其他状态和简单解读
- 死锁,Deadlock(重点关注)
- 执行中,Runnable
- 等待资源,Waiting on condition(重点关注)
- 等待获取监视器,Waiting on monitor entry(重点关注)
- 暂停,Suspended
- 对象等待中,Object.wait() 或 TIMED_WAITING
- 阻塞,Blocked(重点关注)
- 停止,Parked