作者:Jay_huaxiao 链接:https://juejin.im/post/5ead8067e51d454da36cf182

如果有一天,你的Java程序长时间停顿,也许是它病了,需要用jstack拍个片子分析分析,才能诊断具体什么病症,是死锁综合征,还是死循环等其他病症,本文我们一起来学习jstack命令~

  • jstack 的功能
  • jstack用法
  • 线程状态等基础回顾
  • 实战案例1:jstack 分析死锁
  • 实战案例2:jstack 分析CPU 过高

jstack 的功能

jstack是JVM自带的Java堆栈跟踪工具,它用于打印出给定的java进程ID、core file、远程调试服务的Java堆栈信息.

jstack prints Java stack traces of Java threads for a given Java process orcore 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用法

jstack 命令格式如下

jstack [ option ] pid jstack [ option ] executable core jstack [ option ] [server-id@]remote-hostname-or-IP 
  • executable Java executable from which the core dump was produced.(可能是产生core dump的java可执行程序)
  • core 将被打印信息的core dump文件
  • remote-hostname-or-IP 远程debug服务的主机名或ip
  • server-id 唯一id,假如一台主机上多个远程debug服务

最常用的是

jstack [option]   // 打印某个进程的堆栈信息

option参数说明如下:

选项 作用 -F 当正常输出的请求不被响应时,强制输出线程堆栈 -m 如果调用到本地方法的话,可以显示C/C++的堆栈 -l 除堆栈外,显示关于锁的附加信息,在发生死锁时可以用jstack -l pid来观察锁持有情况

线程状态等基础回顾

线程状态简介

jstack用于生成线程快照的,我们分析线程的情况,需要复习一下线程状态吧,拿小凳子坐好,复习一下啦~

Java语言定义了6种线程池状态:

  • New:创建后尚未启动的线程处于这种状态,不会出现在Dump中。
  • RUNNABLE:包括Running和Ready。线程开启start()方法,会进入该状态,在虚拟机内执行的。
  • Waiting:无限的等待另一个线程的特定操作。
  • Timed Waiting:有时限的等待另一个线程的特定操作。
  • 阻塞(Blocked):在程序等待进入同步区域的时候,线程将进入这种状态,在等待监视器锁。
  • 结束(Terminated):已终止线程的线程状态,线程已经结束执行。

Dump文件的线程状态一般其实就以下3种:

  • RUNNABLE,线程处于执行中
  • BLOCKED,线程被阻塞
  • WAITING,线程正在等待

Monitor 监视锁

因为Java程序一般都是多线程运行的,Java多线程跟监视锁环环相扣,所以我们分析线程状态时,也需要回顾一下Monitor监视锁知识。

有关于线程同步关键字Synchronized与监视锁的爱恨情仇,有兴趣的伙伴可以看一下我这篇文章 Synchronized解析——如果你愿意一层一层剥开我的心

Monitor的工作原理图如下:

  • 线程想要获取monitor,首先会进入Entry Set队列,它是Waiting Thread,线程状态是Waiting for monitor entry。
  • 当某个线程成功获取对象的monitor后,进入Owner区域,它就是Active Thread。
  • 如果线程调用了wait()方法,则会进入Wait Set队列,它会释放monitor锁,它也是Waiting Thread,线程状态in Object.wait()
  • 如果其他线程调用 notify() / notifyAll() ,会唤醒Wait Set中的某个线程,该线程再次尝试获取monitor锁,成功即进入Owner区域。

Dump 文件分析关注重点

  • runnable,线程处于执行中
  • deadlock,死锁(重点关注)
  • blocked,线程被阻塞 (重点关注)
  • Parked,停止
  • locked,对象加锁
  • waiting,线程正在等待
  • waiting to lock 等待上锁
  • Object.wait(),对象等待中
  • waiting for monitor entry 等待获取监视器(重点关注)
  • Waiting on condition,等待资源(重点关注),最常见的情况是线程在等待网络的读写

实战案例1:jstack 分析死锁问题

  • 什么是死锁?
  • 如何用jstack排查死锁?

什么是死锁?

死锁是指两个或两个以上的线程在执行过程中,因争夺资源而造成的一种互相等待的现象,若无外力作用,它们都将无法进行下去。

如何用如何用jstack排查死锁问题

先来看一段会产生死锁的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都是只执行到一半,就陷入了阻塞等待状态~

jstack排查Java死锁步骤

  • 在终端中输入jsp查看当前运行的java程序
  • 使用 jstack -l pid 查看线程堆栈信息
  • 分析堆栈信息

在终端中输入jsp查看当前运行的java程序

通过使用 jps 命令获取需要监控的进程的pid,我们找到了23780 DeathLockTest

使用 jstack -l pid 查看线程堆栈信息

由上图,可以清晰看到死锁信息:

  • mythread-tianluo 等待这个锁 “0x00000000d61ae3a0”,这个锁是由于mythread-jay线程持有。
  • mythread-jay线程等待这个锁“0x00000000d61ae3d0”,这个锁是由mythread-tianluo 线程持有。

还原死锁真相

“mythread-tianluo"线程堆栈信息分析如下:

  • mythread-tianluo的线程处于等待(waiting)状态,持有“0x00000000d61ae3d0”锁,等待“0x00000000d61ae3a0”的锁

“mythread-jay"线程堆栈信息分析如下:

  • mythread-tianluo的线程处于等待(waiting)状态,持有“0x00000000d61ae3a0”锁,等待“0x00000000d61ae3d0”的锁

实战案例2:jstack 分析CPU过高问题

来个导致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;                }            }        }    }}

jstack 分析CPU过高步骤

  • top
  • top -Hp pid
  • jstack pid
  • jstack -l [PID] >/tmp/log.txt
  • 分析堆栈信息

1.top

在服务器上,我们可以通过top命令查看各个进程的cpu使用情况,它默认是按cpu使用率由高到低排序的

由上图中,我们可以找出pid为21340的java进程,它占用了最高的cpu资源,凶手就是它,哈哈!

2. top -Hp pid

通过top -Hp 21340可以查看该进程下,各个线程的cpu使用情况,如下:

可以发现pid为21350的线程,CPU资源占用最高~,嘻嘻,小本本把它记下来,接下来拿jstack给它拍片子~

3. jstack pid

通过top命令定位到cpu占用率较高的线程之后,接着使用jstack pid命令来查看当前java进程的堆栈状态,jstack 21350后,内容如下:

4. jstack -l [PID] >/tmp/log.txt

其实,前3个步骤,堆栈信息已经出来啦。但是一般在生成环境,我们可以把这些堆栈信息打到一个文件里,再回头仔细分析哦~

5. 分析堆栈信息

我们把占用cpu资源较高的线程pid(本例子是21350),将该pid转成16进制的值

在thread dump中,每个线程都有一个nid,我们找到对应的nid(5366),发现一直在跑(24行)

这个时候,可以去检查代码是否有问题啦~ 当然,也建议隔段时间再执行一次stack命令,再一份获取thread dump,毕竟两次拍片结果(jstack)对比,更准确嘛~

整理了几百本各类技术电子书相送 ,嘘~,「免费」 送给小伙伴们,私信或者评论【666】自行领取。和一些小伙伴们建了一个技术交流群,一起探讨技术、分享技术资料,旨在共同学习进步。

java命令_Java程序员,不得不会的JDK jstack命令工具相关推荐

  1. chrome java插件_Java程序员喜欢的10款软件里有你在用的吗?

    作为一名Java程序员,日常开发的过程中,我们需要借助很多工具来进行编码.好的工具可以极大的提升程序员的工作效率,今天我们来认识下大多数程序员喜欢的10款软件.持不同意见或有想要补充的小伙伴,欢迎评论 ...

  2. java书籍_Java程序员必看的 13 本 Java 书籍!

    原文:Java程序员必看的 13 本 Java 书籍! 作者: java技术栈 关乎于程序员,除了做项目来提高自身的技术,还有一种提升自己的专业技能就是:多!看!书! 毕竟,书是学习的海洋呢!So,J ...

  3. tomcat如何修改java版本_Java程序员必备——Tomcat配置技巧Top10

    一.配置系统管理(Admin Web Application) 大多数商业化的J2EE服务器都提供一个功能强大的管理界面,且大都采用易于理解的Web应用界面.Tomcat按照自己的方式,同样提供一个成 ...

  4. java过剩_Java程序员的未来发展之路,你是否感到迷茫?你不知道的Java现状

    Java的生态圈决定了这门语言在未来10年都会是最热门的语言之一,因为Java技术具有卓越的通用性.高效性.安全性和平台移植性,它可以跨平台的应用到不同的领域,工作需求足够大. 但也有很多人一直在说J ...

  5. java走向_Java 程序员走向“人生巅峰”的20个建议

    作为一个程序员,在提高自己技能的同时,也要提高自己的思维方式.以下20条建议,可以帮助我们成为一个专业的coder,专业的技术人员. (1) 熟悉工具 军人手中有枪,农民手中有锄头,而我们手中有Jav ...

  6. java查看日志命令_Java程序员必备:查看日志常用的linux命令

    前言 趁周末,复习一下鸟哥的linux私房菜,看了文件内容查阅部分,做个笔记,哈哈,希望对你有帮助哦. cat cat : 由第一行开始显示文件所有内容 参数说明cat[-AbEnTv] 参数: -A ...

  7. java葵花宝典_JAVA程序员想入职跳槽,这些基本功一定要做好,你给自己打几分?...

    基础篇 Q1 访问修饰符 public , private , protected 以及不写时的区别? 类的成员不写访问修饰符时,默认的是default. Q2 Stirng是最基本的数据类型吗? 不 ...

  8. 现在的游戏都是java吗_Java程序员:工作还是游戏,是该好好衡量一下了

    前阵子我终于下定决心,删掉了硬盘里所有的游戏. 身为一个程序猿,每天都要和各种新技术打交道,闲暇时间,总还得看一下各大论坛,逛逛博客园啥的,给自己充充电.游戏的话,其实我自小就比较喜欢,可以算是一种兴 ...

  9. java职级_Java程序员等级怎么划分?

    技术不同.简单的可以理解为:初级中级的只关注代码,编程.高级的就要考虑系统的架构,整体框架. 一.初级部分 1.Java 程序设计基础,包括 J2sdk基础.Java面向对象基础.Java API使用 ...

最新文章

  1. Java 判断list中是否包含某个元素
  2. 设置***遇到一个小问题
  3. 预备作业02 20162320刘先润
  4. python创建txt文件
  5. 如何让带有批注等修改痕迹的word文档编程“正规”文档?
  6. java 时间格式化_彻底解决Spring mvc中时间的转换和序列化等问题
  7. scala教程之:可见性规则
  8. 第六节:用audio标签打造一个属于自己的HTML5音乐播放器
  9. 自动化构建部署之Jenkins安装【Docker容器】
  10. linux网络流量监测工具,linux下网络流量监控工具
  11. 20154319 实验九web安全基础实践
  12. 第三章CDMA的原理和应用(1)
  13. python作排产计划_排产计划表
  14. JAVA Reflect反射详解
  15. 123457123456#0#-----com.yuming.HitMouse01--前拼后广--幼儿打地鼠游戏
  16. 4 java多线程和高并发(待更新)
  17. VirtualBox虚拟电脑控制台错误,不能为虚拟电脑打开一个新任务
  18. Android 模拟器中的menu键
  19. Excel公式提取数据
  20. 毛利率、净利率和成本利润率的区别是什么 ?

热门文章

  1. Bailian2698 八皇后【回溯】
  2. AOJ0008 Sum of 4 Integers【暴力】
  3. NUC1154 Vertical Histogram【打印图案】
  4. Python 爬虫 —— 文件及文件夹操作
  5. 数据科学(data science)概览
  6. [面试] 算法(七)—— 逆序输出链表
  7. 黄金分割比的重新理解
  8. python 模块定义_在python中定义私有模块函数
  9. qml中使用combobox实现多级菜单_Excel教程:还不会做Excel三级下拉菜单?其实它跟复制粘贴一样简单...
  10. vector java 复制_Java代码性能优化的 40+ 细节