Jstack 用法
$ jstack -help
Usage:
jstack [-l] <pid>
(to connect to running process)
jstack -F [-m] [-l] <pid>
(to connect to a hung process)
jstack [-m] [-l] <executable> <core>
(to connect to a core file)
jstack [-m] [-l] [server_id@]<remote server IP or hostname>
(to connect to a remote debug server)
Options:
-F to force a thread dump. Use when jstack <pid> 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
参数说明:
- -l 长列表. 打印关于锁的附加信息,例如属于java.util.concurrent 的 ownable synchronizers列表
- -F 当’jstack [-l] pid’没有相应的时候强制打印栈信息
- -m 打印java和native c/c++框架的所有栈信息
- -h | -help 打印帮助信息
- pid 需要被打印配置信息的java进程id,可以用jps查询
Jstack 使用
通过使用 jps 命令获取需要监控的进程的pid,然后使用 jstack pid 命令查看线程的堆栈信息。
$ jstack 4628
2019-05-08 13:52:47
Full thread dump Java HotSpot(TM) 64-Bit Server VM (25.161-b12 mixed mode):
"NettythreadDeathWatcher-2-1" #17 daemon prio=1 os_prio=-2 tid=0x0000000018473800 nid=0x5aa4 waiting on condition [0x000000001b9af000]
java.lang.Thread.State: TIMED_WAITING (sleeping)
at java.lang.Thread.sleep(Native Method)
at io.netty.util.ThreadDeathWatcher$Watcher.run(ThreadDeathWatcher.java:152)
at io.netty.util.concurrent.DefaultThreadFactory$DefaultRunnableDecorator.run(DefaultThreadFactory.java:138)
at java.lang.Thread.run(Thread.java:748)
"DestroyJavaVM" #15 prio=5 os_prio=0 tid=0x0000000018476800 nid=0x2a28 waiting on condition [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
"JPS event loop" #10 prio=5 os_prio=0 tid=0x00000000175d1000 nid=0x4cac runnable [0x0000000017b8f000]
java.lang.Thread.State: RUNNABLE
at sun.nio.ch.WindowsSelectorImpl$SubSelector.poll0(Native Method)
at sun.nio.ch.WindowsSelectorImpl$SubSelector.poll(WindowsSelectorImpl.java:296)
at sun.nio.ch.WindowsSelectorImpl$SubSelector.access$400(WindowsSelectorImpl.java:278)
at sun.nio.ch.WindowsSelectorImpl.doSelect(WindowsSelectorImpl.java:159)
at sun.nio.ch.SelectorImpl.lockAndDoSelect(SelectorImpl.java:86)
- locked <0x00000000d541b7c0> (a io.netty.channel.nio.SelectedSelectionKeySet)
- locked <0x00000000d541b7b0> (a java.util.Collections$UnmodifiableSet)
- locked <0x00000000d541b730> (a sun.nio.ch.WindowsSelectorImpl)
at sun.nio.ch.SelectorImpl.select(SelectorImpl.java:97)
at io.netty.channel.nio.SelectedSelectionKeySetSelector.select(SelectedSelectionKeySetSelector.java:62)
at io.netty.channel.nio.NioEventLoop.select(NioEventLoop.java:752)
at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:408)
at io.netty.util.concurrent.SingleThreadEventExecutor$5.run(SingleThreadEventExecutor.java:858)
at java.lang.Thread.run(Thread.java:748)
通过 jstack 命令可以获取当前进程的所有线程信息。
每个线程堆中信息中,都可以查看到 线程ID、线程的状态(wait、sleep、running 等状态)、是否持有锁信息等。
死锁示例
下面通过一个例子,来演示 jstack 检查死锁的一个例子,代码如下:
public static void deathLock() {
Thread t1 = new Thread() {
@Override
public void run() {
try {
lock1.lock();
TimeUnit.SECONDS.sleep(1);
lock2.lock();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
};
Thread t2 = new Thread() {
@Override
public void run() {
try {
lock2.lock();
TimeUnit.SECONDS.sleep(1);
lock1.lock();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
};
t1.setName("mythread1");
t2.setName("mythread2");
t1.start();
t2.start();
}
使用 jstack -l pid 查看线程堆栈信息,发现在堆栈信息最后面检查出了一个死锁。如下图
可以清楚的看出 mythread2 等待 这个锁 “0x00000000d6eb82d0”,这个锁是由于mythread1线程持有。
mythread1线程等待这个锁“0x00000000d6eb8300”,这个锁是由mythread2线程持有。
“mythread1”线程堆栈信息如下:
可以看出当前线程持有“0x00000000d6eb82d0”锁,等待“0x00000000d6eb8300”的锁
“mythread2”线程堆栈信息如下:
“mythread2”的堆栈信息中可以看出当前线程持有“0x00000000d6eb8300”锁,等待“0x00000000d6eb82d0”的锁。