Java中死锁的定位与修复

死锁应该可以说是并发编程中比较常见的一种情况,可以说如果程序产生了死锁那将会对程序带来致命的影响;所以排查定位、修复死锁至关重要;

我们都知道死锁是由于多个对象或多个线程之间相互需要 对方锁持有的锁而又没有释放对方所持有的锁,导致双方都永久处于阻塞状态 ;

如上图所示,线程1持有对象1的锁、线程2持有对象2的锁,持此线程1又想去获取对象2对象锁、线程2想获取对象1对象锁,此时由于双方都没有获取到想要的锁,任务没完成所以也没释放锁,导致一直僵持呢,于是阻塞、产生死锁;

死锁检测

需要检测死锁肯定要先有死锁出现,下面的demo模拟了一个死锁的产生;

public class SynchronizedDeadLock {

    private static final Object lockA = new Object();
    private static final Object lockB = new Object();

    public static void main(String[] args) {
        new ThreadA().start();
        new ThreadB().start();
    }

    /**
     * ThreadA先获取lockA,在获取lockB
     */
    private static class ThreadA extends java.lang.Thread {

        @Override
        public void run() {
            // 获取临界区A
            synchronized (lockA) {
                System.out.println(Thread.currentThread().getName()+" get lockA success");
                // 模拟耗时操作
                try {
                    Thread.sleep(500);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                // 获取临界区B
                synchronized (lockB) {
                    System.out.println(Thread.currentThread().getName()+" get lockB success");
                }
            }
        }
    }

    /**
     * ThreadB先获取lockB,在获取lockA
     */
    private static class ThreadB extends java.lang.Thread {

        @Override
        public void run() {
            // 获取临界区A
            synchronized (lockB) {
                System.out.println(Thread.currentThread().getName()+" get lockB success");
                // 模拟耗时操作
                try {
                    Thread.sleep(500);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                // 获取临界区B
                synchronized (lockA) {
                    System.out.println(Thread.currentThread().getName()+" get lockA success");
                }
            }
        }
    }
}

这demo没法结束运行就是由于产生了死锁,两个线程都在相互对待获取对方所持有的对象锁;

这时候要解决问题就需要找出哪里出现了死锁, 通过代码走查通常不容易发现死锁 ,当然我们这程序很容易发现,因为我们刻意产生的死锁;所以就需要工具来检测死锁,这里可用的工具主要有:jconsole、jvisualvm、jstack等,这些工具其实都是jdk自带的,用法都很类似;

这里使用jvisualvm来检测当前的demo程序是否产生了死锁;打开jvisualvm连接到当前的应用程序即可看到程序的监控信息,如内存、CPU、性能、GC等等;打开进入线程的tab项查看程序的线程信息,这里很明显的就看到了提示该程序被检测除了死锁!

点击 线程Dump可以看到线程的堆栈信息,从中可以看到线程的详细信息,并定位死锁;

从上图可以看到线程产生死锁的原因,Thrad2是等待Thread1、Thread1是等待Thread1, 从下图的堆栈信息即可定位死锁产生的位置;

避免死锁

解决死锁最好的方法就是避免死锁了,比如上面的demo我们可以把直接使用无参数的lock()方法换为使用tryLock方法,tryLock还可以指定获取锁超时时间,到了超时时间还没获得到锁就会放弃获取锁,当然还有其它方法可以避免死锁;

1、避免使用多个锁、长时间持有锁;

2、设计好多个锁的获取顺序

3、使用带超时的获取锁方法
 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值