jstack实战死锁与死循环

使用场景

当我们的线上程序 CPU 飙高的时候、线程发生死锁的时候等,我们需要排查这些情况,那如何查看进程里的线程信息呢?这个时候需要将进程内的线程运行状态进行转储,好进行分析,这个时候就需要使用 jstack进行分析

基本用法
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

基本用法写的很清楚

jstack操作演示

下面以 tomcat 演示一下基本的操作过程。

我首先打开一个 tomcat 进程并启动,使用 jps -l 查看正在运行的 java 进程信息

在这里插入图片描述

可以看到 tomcat 所在的进程 id 为 17408,接着使用命令jstack 17408 > 17408.txt生成一个文件,使用文本编辑器打开

// 插入图片

几个参数说明:#40 这表示线程编号,daemon表示这是守护线程,prio=5 os_prio=0表示线程的优先级以及系统的优先级,java.lang.Thread.State: RUNNABLE表示这个线程处于什么状态

文件中还有许多其他的线程,包括 GC 线程,main 线程等等
在这里插入图片描述
在这里插入图片描述

jstack实战死锁

这一节我们通过手动构造一个死锁,然后使用 jstack 进行排查

@RestController
@RequestMapping("/cpu")
public class CpuController {

    private Object lock1 = new Object();
    private Object lock2 = new Object();

    @RequestMapping("/deadlock")
    public String deadLock() {
        new Thread(() -> {
            synchronized (lock1) {
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                synchronized (lock2) {
                    System.out.println("lock1获取lock2成功");
                }
            }
        }).start();
        new Thread(() -> {
            synchronized (lock2) {
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                synchronized (lock1) {
                    System.out.println("lock2获取lock1成功");
                }
            }
        }).start();
        return "deadlock";
    }
}

跑起来之后使用 jstack 转储
在这里插入图片描述
打开文件拖到最后如下所示
在这里插入图片描述
可以发现,jstack 自动发现了一个死锁,并且定位到了死锁的位置,通过查看看信息可以知道, waiting to lock <0x00000000ff00bce8>,可以很轻松的定位到死锁的位置。这是我们手动构造的,所以就算不用 jstack 也很容易知道问题,但是实际项目代码量很多,如果依靠自己去排查,难度是相当高的,所以借助 jstack 能够很轻松的知道问题所在

jstack实战死循环

使用 jstack 的另一种场景就是死循环的发生,导致的直接后果就是 CPU 利用率飙高,一旦使用率飙高之后,就会阻塞其他的访问。这里我提供一个思路,由于我是在 Windows下跑的,Linux的命令无法使用,只能使用资源管理器进行查看,代码也很简单,我在访问的函数接口中构造一个死循环,当访问这个接口的时候就会死循环,我开了四个窗口访问这个接口,结果上使用资源管理器查看 CPU 已经跑满 100% 了,那么在 Linux 下该如何定位这个问题呢?
首先查看正在跑的程序的 pid,然后使用 top 命令进行查看top -p pid H,前几个就是 CPU占用率特别高的,记住前面的 pid数字,转成 16 进制,因为 jstack 内部表示 pid是使用 16 进制表示的。然后发开转储文件,搜索对应的 pid 号,查看具体的堆栈信息,里面包含了函数调用情况,一般来说能够大致的解决问题。
这里先留个坑,Linux下的死循环问题等以后补上

总结

这里简单的介绍了 jstack 的使用情况,以及简单的案例进行分析 jstack 是如何定位死锁以及死循环的问题,在实际中可以多多的进行模拟分析。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值