若是有一天,你的Java程序长时间停顿,也许是它病了,须要用jstack拍个片子分析分析,才能诊断具体什么病症,是死锁综合征,仍是死循环等其余病症,本文咱们一块儿来学习jstack命令~java
jstack是JVM自带的Java堆栈跟踪工具,它用于打印出给定的java进程ID、core file、远程调试服务的Java堆栈信息.git
jstack prints Java stack traces of Java threads for a given Java process or core file or a remote debug server.
- jstack命令用于生成虚拟机当前时刻的线程快照。
- 线程快照是当前虚拟机内每一条线程正在执行的方法堆栈的集合,生成线程快照的主要目的是定位线程出现长时间停顿的缘由,
如线程间死锁、死循环、请求外部资源致使的长时间等待等问题。- 线程出现停顿的时候经过jstack来查看各个线程的调用堆栈,就能够知道没有响应的线程到底在后台作什么事情,或者等待什么资源。
- 若是java程序崩溃生成core文件,jstack工具能够用来得到core文件的java stack和native stack的信息,从而能够轻松地知道java程序是如何崩溃和在程序何处发生问题。
- 另外,jstack工具还能够附属到正在运行的java程序中,看到当时运行的java程序的java stack和native stack的信息, 若是如今运行的java程序呈现hung的状态,jstack是很是有用的。
jstack 命令格式以下github
jstack [ option ] pid jstack [ option ] executable core jstack [ option ] [server-id@]remote-hostname-or-IP
最经常使用的是服务器
jstack [option] <pid> // 打印某个进程的堆栈信息
option参数说明以下:网络
选项 | 做用 |
---|---|
-F | 当正常输出的请求不被响应时,强制输出线程堆栈 |
-m | 若是调用到本地方法的话,能够显示C/C++的堆栈 |
-l | 除堆栈外,显示关于锁的附加信息,在发生死锁时能够用jstack -l pid来观察锁持有状况 |
jstack用于生成线程快照的,咱们分析线程的状况,须要复习一下线程状态吧,拿小凳子坐好,复习一下啦~
多线程
Java语言定义了6种线程池状态:jvm
Dump文件的线程状态通常其实就如下3种:jsp
由于Java程序通常都是多线程运行的,Java多线程跟监视锁环环相扣,因此咱们分析线程状态时,也须要回顾一下Monitor监视锁知识。ide
有关于线程同步关键字Synchronized与监视锁的爱恨情仇,有兴趣的伙伴能够看一下我这篇文章
Synchronized解析——若是你愿意一层一层剥开个人心工具
Monitor的工做原理图以下:
死锁是指两个或两个以上的线程在执行过程当中,因争夺资源而形成的一种互相等待的现象,若无外力做用,它们都将没法进行下去。
先来看一段会产生死锁的Java程序,源码以下:
/** * Java 死锁demo */ public class DeathLockTest { private static Lock lock1 = new ReentrantLock(); private static Lock lock2 = new ReentrantLock(); public static void deathLock() { Thread t1 = new Thread() { @Override public void run() { try { lock1.lock(); System.out.println(Thread.currentThread().getName() + " get the lock1"); Thread.sleep(1000); lock2.lock(); System.out.println(Thread.currentThread().getName() + " get the lock2"); } catch (InterruptedException e) { e.printStackTrace(); } } }; Thread t2 = new Thread() { @Override public void run() { try { lock2.lock(); System.out.println(Thread.currentThread().getName() + " get the lock2"); Thread.sleep(1000); lock1.lock(); System.out.println(Thread.currentThread().getName() + " get the lock1"); } catch (InterruptedException e) { e.printStackTrace(); } } }; //设置线程名字,方便分析堆栈信息 t1.setName("mythread-jay"); t2.setName("mythread-tianluo"); t1.start(); t2.start(); } public static void main(String[] args) { deathLock(); } }
运行结果:
显然,线程jay和线程tianluo都是只执行到一半,就陷入了阻塞等待状态~
经过使用 jps 命令获取须要监控的进程的pid,咱们找到了23780 DeathLockTest
由上图,能够清晰看到死锁信息:
“mythread-tianluo"线程堆栈信息分析以下:
“mythread-jay"线程堆栈信息分析以下:
来个致使CPU太高的demo程序,一个死循环,哈哈~
/** * 有个致使CPU太高程序的demo,死循环 */ public class JstackCase { private static ExecutorService executorService = Executors.newFixedThreadPool(5); public static void main(String[] args) { Task task1 = new Task(); Task task2 = new Task(); executorService.execute(task1); executorService.execute(task2); } public static Object lock = new Object(); static class Task implements Runnable{ public void run() { synchronized (lock){ long sum = 0L; while (true){ sum += 1; } } } } }
在服务器上,咱们能够经过top命令查看各个进程的cpu使用状况,它默认是按cpu使用率由高到低排序的
由上图中,咱们能够找出pid为21340的java进程,它占用了最高的cpu资源,凶手就是它,哈哈!
经过top -Hp 21340能够查看该进程下,各个线程的cpu使用状况,以下:
能够发现pid为21350的线程,CPU资源占用最高,嘻嘻,小本本把它记下来,接下来拿jstack给它拍片子
经过top命令定位到cpu占用率较高的线程以后,接着使用jstack pid命令来查看当前java进程的堆栈状态,jstack 21350
后,内容以下:
其实,前3个步骤,堆栈信息已经出来啦。可是通常在生成环境,咱们能够把这些堆栈信息打到一个文件里,再回头仔细分析哦~
咱们把占用cpu资源较高的线程pid(本例子是21350),将该pid转成16进制的值
在thread dump中,每一个线程都有一个nid,咱们找到对应的nid(5366),发现一直在跑(24行)
这个时候,能够去检查代码是否有问题啦~ 固然,也建议隔段时间再执行一次stack命令,再一份获取thread dump,毕竟两次拍片结果(jstack)对比,更准确嘛~