jstack命令详解
简介
- jstack命令用于打印指定Java进程、核心文件或远程调试服务器的Java线程的Java堆栈跟踪信息[1]。
- jstack命令可以生成JVM当前时刻的线程快照。线程快照是当前JVM内每一条线程正在执行的方法堆栈的集合,生成线程快照的主要目的是定位线程出现长时间停顿的原因,如线程间死锁、死循环、请求外部资源导致的长时间等待等。
- 如果java程序崩溃生成core文件,jstack工具可以用来获得core文件的java stack和native stack的信息,从而可以轻松地知道java程序是如何崩溃和在程序何处发生问题。
- 当指定的进程在64位Java虚拟机上运行时,可能需要指定-J-d64选项,例如:jstack -J-d64 -m pid。
- 该命令可能在未来的版本中不可用!!!
语法
jstack [ options ] pid
pid:Java进程的ID,可以通过jps命令查询到。
jstack [ options ] executable core
executable: 产生core dump的Java可执行程序
core:要打印的堆栈跟踪的核心文件
jstack [ options ] [ server-id@ ] remote-hostname-or-IP
server-id:当多个DEBUG服务器在同一远程主机上运行时,可使用的可选唯一ID。
remote-hostname-or-IP:远程DEBUG的服务器主机名或IP地址
options 参数说明
-F
当 jstack [-l] pid 没有响应时,强制打印一个堆栈转储。
-l
打印关于锁的其他信息,比如拥有的java.util.concurrent ownable同步器的列表。
-m
打印包含Java和本机C/ C++帧的混合模式堆栈跟踪。
-h
打印帮助信息
-help
打印帮助信息
例子
jstack pid
jstack -F pid
jstack -l pid
jstack -m pid
jstack -h pid
jstack -H pid
日志文件分析
- 可以通过 jstack [options] pid >> /xxx/xx/x/dump.log命令,将堆栈信息输出到dump.log文件后,然后下载到本地排查文件。
- 在dump.log日志文件里,需要重点关注的线程状态
Deadlock(死锁)
死锁线程,一般指多个线程调用间,进入相互资源占用,导致一直等待无法释放的情况。
1、死锁代码如下
package com.example;
public class Test {
public static void main(String[] args) {
Thread a = new MyThreadA();
Thread b = new MyThreadB();
a.setName("线程A");
a.start();
b.setName("线程B");
b.start();
}
}
class MyThreadA extends Thread {
@Override
public void run() {
System.out.println("================B===================");
synchronized (A.A) {
System.out.println("线程【" + Thread.currentThread().getName() + "】开始执行");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (B.B) {
}
System.out.println("线程【" + Thread.currentThread().getName() + "】执行结束。B.B = " + B.B + "; A.A = " + A.A);
}
}
}
class MyThreadB extends Thread {
@Override
public void run() {
System.out.println("================B===================");
synchronized (B.B) {
System.out.println("线程【" + Thread.currentThread().getName() + "】开始执行");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (A.A) {
}
System.out.println("线程【" + Thread.currentThread().getName() + "】执行结束。B.B = " + B.B
