死锁

作者: OPice | 来源:发表于2019-11-20 12:01 被阅读0次

    什么是死锁

    简单的说:线程1持有A锁,线程2持有B锁;线程1尝试获取B锁,线程2尝试获取A锁。两个线程各持有了一把锁,同时想获取对方的锁,自身的又不释放。


    死锁

    如何定位

    先写一个死锁的程序

    public class DeadLock extends Thread {
        private String first;
        private String second;
    
        public DeadLock(String first, String second) {
            this.first = first;
            this.second = second;
        }
    
        public void run() {
            synchronized (first) {
                System.out.println(this.getName() + ":" + first);
                try {
                    Thread.sleep(2000);
                    synchronized (second) {
                        System.out.println(this.getName() + ":" + second);
                    }
                } catch (InterruptedException e) {
    
                }
            }
        }
    
        public static void main(String[] args) throws InterruptedException {
            String lockA = "锁A";
            String lockB = "锁B";
            DeadLock thread1 = new DeadLock(lockA, lockB);
            DeadLock thread2 = new DeadLock(lockB, lockA);
    
            thread1.start();
            thread2.start();
            thread1.join();
            thread2.join();
        }
    }
    

    执行结果:

    Thread-0:锁A
    Thread-1:锁B
    

    几乎每次都会出现死锁的情况,如果项目中遇到这种问题如何排查:

    1. 使用jdk原生工具jstack

    使用jps或者ps确定进程ID,然后执行 jstack PID

    image.png
    可以清楚看到Thread1 和Thread0 互相等待对方锁。

    2.使用MXBean工具

    修改示例中的main方法,使用MXBean的findDeadLockedThreads方法

     public static void main(String[] args) throws InterruptedException {
            ThreadMXBean threadMXBean = ManagementFactory.getThreadMXBean();
            Runnable runnable = new Runnable() {
                @Override
                public void run() {
                    long[] allThreadIds = threadMXBean.findDeadlockedThreads();
                    if (allThreadIds != null){
                        ThreadInfo[] threadInfo = threadMXBean.getThreadInfo(allThreadIds);
                        System.out.println("deadLock threads:");
                        for (ThreadInfo t :threadInfo) {
                            System.out.println(t.getThreadName());
                        }
                    }
                }
            };
    
            ScheduledThreadPoolExecutor scheduled = new ScheduledThreadPoolExecutor(1);
            //等待10s,每10s检查一次
            scheduled.scheduleAtFixedRate(runnable,10,10, TimeUnit.SECONDS);
    
            String lockA = "锁A";
            String lockB = "锁B";
            DeadLock thread1 = new DeadLock(lockA, lockB);
            DeadLock thread2 = new DeadLock(lockB, lockA);
    
            thread1.start();
            thread2.start();
            thread1.join();
            thread2.join();
        }
    

    执行结果

    Thread-0:锁A
    Thread-1:锁B
    deadLock threads:
    Thread-1
    Thread-0
    deadLock threads:
    Thread-1
    Thread-0
    

    如何避免

    当程序发生死锁不仅排查起来耗时,而且只能重启,修改程序本身代码来弥补。所以当写程序的时候如何避免死锁显得重要的多。

    从代码程序上

    • 不要出现多个锁
    • 设置锁的过期时间

    工具上

    • 使用静态代码扫描,例如“FindBugs”

    其他方式

    • 写之前把使用锁的逻辑画出流程图
    • 类加载过程中发生的死锁 参考:官方文档

    最后

    自旋锁发生死锁如何排查,程序中经常遇到的OOM 排查方式一样。
    top查看下CPU使用最高的进程,然后打出堆栈信息排查代码。

    内存泄漏排查:
    记一次内存泄漏排查

    相关文章

      网友评论

        本文标题:死锁

        本文链接:https://www.haomeiwen.com/subject/zomnictx.html