始于足下.|

MuXinu

园龄:2年7个月粉丝:3关注:1

jstack命令示例(CPU100%&死锁排查流程)

先说结论:

排查Java死锁

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

分析CPU过高(100%)问题

# P(shift+p) cpu排序 找到cpu占用高的 pid
top
# -H 可以查看由某个进程启动的所有线程 P cpu排序找到最大线程 pid 这里为 tid
top -Hp <pid>
# 将 tid 转 16进制  因为 jstack 输出的进程栈信息中,线程ID是以十六进制展示
printf "%x\n" <tid>
# jstack pid | grep '<16进制 tid>'
# -A 100 输出 100 行
jstack <pid> | grep '<16进制 tid>' -A 100 > ./cpu-100.txt

 

关联知识

jstack

jstack是JVM自带的Java堆栈跟踪工具,它用于打印出给定的java进程ID、core file、远程调试服务的Java堆栈信息.
  • jstack命令用于生成虚拟机当前时刻的线程快照。
  • 线程快照是当前虚拟机内每一条线程正在执行的方法堆栈的集合,生成线程快照的主要目的是定位线程出现长时间停顿的原因, 如线程间死锁、死循环、请求外部资源导致的长时间等待等问题。
  • 线程出现停顿的时候通过jstack来查看各个线程的调用堆栈,就可以知道没有响应的线程到底在后台做什么事情,或者等待什么资源。
  • 如果java程序崩溃生成core文件,jstack工具可以用来获得core文件的java stack和native stack的信息,从而可以轻松地知道java程序是如何崩溃和在程序何处发生问题。
  • 另外,jstack工具还可以附属到正在运行的java程序中,看到当时运行的java程序的java stack和native stack的信息, 如果现在运行的java程序呈现hung的状态,jstack是非常有用的。
jstack使用格式:
Usage:
jstack [-l][-e] <pid>
(to connect to running process)
Options:
-l  long listing. Prints additional information about locks
-e  extended listing. Prints additional information about threads
-? -h --help -help to print this help message

 线程状态

Java语言定义了6种线程池状态:
  • 初始(NEW):新创建了一个线程对象,但还没有调用start()方法。
  • 运行(RUNNABLE):Java线程中将就绪(ready)和运行中(running)两种状态笼统的称为“运行”。
  • 线程对象创建后,其他线程(比如main线程)调用了该对象的start()方法。该状态的线程位于可运行线程池中,等待被线程调度选中,获取CPU的使用权,此时处于就绪状态(ready)。就绪状态的线程在获得CPU时间片后变为运行中状态(running)。
  • 阻塞(BLOCKED):表示线程阻塞于锁。
  • 等待(WAITING):进入该状态的线程需要等待其他线程做出一些特定动作(通知或中断)。
  • 超时等待(TIMED_WAITING):该状态不同于WAITING,它可以在指定的时间后自行返回。
  • 终止(TERMINATED):表示该线程已经执行完毕。

 

 Monitor 监视锁

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,等待资源(重点关注),最常见的情况是线程在等待网络的读写

死锁排查实战

死锁代码
 /**
 * 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();
    }
}

 执行DeathLockTest:

发现程序进入阻塞状态,无法结束

0
 
在命令行输入 jps 命令查询:
 
 
找到我们需要打印堆栈的PID,如图找到 22639
 
jstack -l 22639 分析堆栈信息
0

jstack 分析CPU过高问题

死循环代码
 /**
 * 有个导致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;
                }
            }
        }
    }
}

 

运行JstackCase(这里在linux环境下演示)
 
各个进程的cpu使用情况,它默认是按cpu使用率由高到低排序的,如图找到PID:29595的Java程序cpu占用100%
0
 
 
top -Hp 29595 查看进程内部的线程执行情况,发现PID:29616的线程cpu占用率较高
0
 
printf "%x\n" 29616 转为十六进制 73b0
0
 
打印出29595进程中,关于29616线程的堆栈信息
jstack 29595 | grep '73b0' -A 100 > ./cpu-100.txt
0
 
 
分析堆栈信息
0

 

 

 

 原文连接:https://juejin.cn/post/6844904152850497543

 

本文作者:MuXinu

本文链接:https://www.cnblogs.com/MuXinu/p/17388443.html

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。

posted @   MuXinu  阅读(1114)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示
评论
收藏
关注
推荐
深色
回顶
收起