线上死锁问题排查思路

Java线上死锁问题排查

死锁是程序开发中经常遇到的问题,参与死锁的线程将无法继续执行,长时间的死锁会导致整个系统卡死

这样一来服务不得不中断从而严重影响用户体验,所以在发生死锁后,尽早的排查出死锁问题,恢复系统运行就显得很重要

案例分析

java 复制代码
public class DeadLockDemo {

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

    public void method1() {
        synchronized (lock1) {
            System.out.println("Method1 持有lock1");
            try {
                Thread.sleep(100);
                synchronized (lock2) {
                    System.out.println("Method1 持有lock2");
                }
            }catch (InterruptedException e){
                System.out.println("Method1 等待获取lock2");
            }
        }
    }

    public void method2() {
        synchronized (lock2) {
            System.out.println("Method2 持有lock2");
            try {
                Thread.sleep(100);
                synchronized (lock1) {
                    System.out.println("Method1 持有lock1");
                }
            }catch (InterruptedException e){
                System.out.println("Method1 等待获取lock1");
            }
        }
    }

    public static void main(String[] args) {
        DeadLockDemo demo = new DeadLockDemo();
        Thread t1 = new Thread(demo::method1,"method1");
        Thread t2 = new Thread(demo::method2,"method2");
        t1.start();
        t2.start();
    }
}

死锁识别及分析

  • 运行程序发现程序一直卡住,进程永远不会结束
  1. 收集线程堆栈信息,在终端执行以下命令,查看应用程序的进程ID
ini 复制代码
jps
  1. 然后将进程ID对应的程序线程日志收集到文本中,方便后续分析
ini 复制代码
jstack -l 39171 > ./deadlockdemo.txt

可以看到在当前目录下生成了一个deadlockdemo.txt文件

  1. 在deadlockdemo.txt文件中搜索deadlock等字样

很明显的可以看到线程thread1和thread2都出现了wating to lock,尝试获取锁,造成了死锁,并定位到具体代码行

  1. 代码分析

代码分析很容易就看出是这里的两个锁定出现了问题,thread1和thread2出现了循环锁定,thread1先锁定了lock1,然后sleep了100ms

再去尝试锁定lock2,而thread2这个时候已经把lock2锁定了,然后thread2又尝试锁定lock1,由于lock1和lock2都被对方持有,不释放

导致thread1和thread2的第二次锁定永远不会成功,从而形成死锁

  1. 代码修正

调整获取锁的顺序,避免出现循环锁定,让thread2也先锁定lock1,然后再锁定lock2,调整后代码如下:

java 复制代码
public class DeadLockDemo {

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

    public void method1() {
        synchronized (lock1) {
            System.out.println("Method1 持有lock1");
            try {
                Thread.sleep(100);
                synchronized (lock2) {
                    System.out.println("Method1 持有lock2");
                }
            }catch (InterruptedException e){
                System.out.println("Method1 等待获取lock2");
            }
        }
    }

    public void method2() {
        synchronized (lock1) {
            System.out.println("Method2 持有lock1");
            try {
                Thread.sleep(100);
                synchronized (lock2) {
                    System.out.println("Method2 持有lock2");
                }
            }catch (InterruptedException e){
                System.out.println("Method2 等待获取lock2");
            }
        }
    }

    public static void main(String[] args) {
        DeadLockDemo demo = new DeadLockDemo();
        Thread t1 = new Thread(demo::method1,"method1");
        Thread t2 = new Thread(demo::method2,"method2");
        t1.start();
        t2.start();
    }
}

总结

线上排查Java死锁问题步骤,简单概括如下:

  1. 识别死锁发生的现象:确定应用是否表现出死锁的症状,如线程长时间处于阻塞状态
  2. 获取线程堆栈的信息:通过工具(如jstack)获取JVM线程堆栈,分析各线程的状态,尤其关注等待锁的线程
  3. 分析代码:检查线程堆栈中的栈帧,定位发生死锁的代码区域。重点关注可能导致锁定的同步块或方法
  4. 优化代码逻辑:修复导致死锁的代码块,一般可以采用减少锁的粒度,使用非阻塞算法,或者重构为无锁设计,使用tryLock()等机制避免长期持有锁等方式
  5. 监控和测试:持续监控应用运行时的线程情况,尤其是在高并发场景下,通过压力测试和代码审计尽早发现潜在的死锁问题
相关推荐
IT_陈寒1 分钟前
深入理解Redis:核心原理与最佳实践
前端·人工智能·后端
打工仔折腾 AI4 分钟前
鸿蒙端ToDesk远控电脑实测:蓝牙键鼠、双模式鼠标与跨端剪贴板实践
后端·python·性能优化·计算机外设·电脑·harmonyos·ai agent 实战
AINative软件工程8 分钟前
LLM 异步任务的 Webhook 工程实践:回调可靠投递、重试与幂等消费的生产设计
后端·ai编程
高频因子挖掘机16 分钟前
Python 批量获取股票行情后,如何用 Pandas 统一字段、索引和数据类型?
后端·github·api
高频因子挖掘机38 分钟前
多股票 K 线如何用 Pandas 对齐?从收益率计算到横截面分析
后端·github·api
架构技术专栏9 小时前
Agent 工具调用:从工具声明到执行反馈
前端·人工智能·后端
码事漫谈10 小时前
你让AI干的活,它可能只干了十分之一——而你根本看不出来
后端
Wx-bishekaifayuan10 小时前
express皖美特色农产品网售系统53118-计算机课程设计、毕业设计
人工智能·spring boot·后端·python·课程设计·express·旅游
Wx-bishekaifayuan11 小时前
springboot汉中旅游服务平台41442-计算机课程设计、毕业设计
spring boot·后端·python·django·课程设计·express·旅游
WeiXin_DZbishe11 小时前
基于springboot城市公交实时运营与调度系统-计算机毕设 附源码【课程设计】66173
java·vue.js·spring boot·后端·python·php·课程设计