死锁与问题排查

2021-01-01  本文已影响0人  ________方块丶

本篇文章从Java线程、锁层面去考虑考虑死锁。

死锁:多个线程,彼此持有对方需要的锁资源,谁也不肯释放,谁也无法进行,而导致的僵死局面。比如:T1持有L1锁,需要L2锁才能运行,T2持有L2锁,需要L1锁才能够运行。

活锁:多个线程,彼此谦让对方需要的锁资源,谁也不能够拥有所资源,谁也没法进行的尴尬局面。比如:T1持有L1锁,发现没法获取到L2锁,立马释放L1,T2持有L2锁,发现没法获取L1锁,立马释放L2锁,如此反复。

死锁产生的四个条件

死锁产生需要依赖下面四个条件,缺一不可

  1. 互斥:共享资源只能被一个线程占用,如T1,T2
  2. 占有且保持:线程T1已占有L1锁资源,再去请求L2锁资源时,并不会释放L1资源。
  3. 不可抢占:其他线程不能争夺T1已经占用的资源。
  4. 循环等待:T1等待T2释放L2,T2等待T1释放L1

简单死锁示例

/**
 * 死锁例子
 * 线程L1 持有L1的情况下,尝试获取L2
 * 线程L2 持有L2的情况下,尝试获取L1
 */
public class DeadLockDemo {
    public static void main(String[] args) {
        Object L1 = new Object();
        Object L2 = new Object();
        Thread T1 = new Thread(() -> {
            while (true) {
                synchronized (L1) {
                    synchronized (L2) {
                        //do something
                    }
                }
            }

        });
        Thread T2 = new Thread(() -> {
            while (true) {
                synchronized (L2) {
                    synchronized (L1) {
                        //do something
                    }
                }
            }
        });
        T1.start();
        T2.start();
    }
}

以上变量明明不值得参考

死锁排查

线程相关的排查比较简单,一般使用jpsjstack命令就可以搞定。

// 首先获取相关JVM的进程编号,可以看到目标JVM进程为6625
jps -l

6624 org.jetbrains.jps.cmdline.Launcher
6625 DeadLockDemo
6626 sun.tools.jps.Jps
4307 org.jetbrains.idea.maven.server.RemoteMavenServer36
382 
// 利用jstack JVM进程号打印线程栈信息,可以看到连个相互等待
jstack 6625


Found one Java-level deadlock:
=============================
"Thread-1":
  waiting to lock monitor 0x00007f8f8a00eeb8 (object 0x000000076ac33cd8, a java.lang.Object),
  which is held by "Thread-0"
"Thread-0":
  waiting to lock monitor 0x00007f8f8a0104b8 (object 0x000000076ac33ce8, a java.lang.Object),
  which is held by "Thread-1"

Java stack information for the threads listed above:
===================================================
"Thread-1":
        at DeadLockDemo.lambda$main$1(DeadLockDemo.java:26)
        - waiting to lock <0x000000076ac33cd8> (a java.lang.Object)
        - locked <0x000000076ac33ce8> (a java.lang.Object)
        at DeadLockDemo$$Lambda$2/668386784.run(Unknown Source)
        at java.lang.Thread.run(Thread.java:748)
"Thread-0":
        at DeadLockDemo.lambda$main$0(DeadLockDemo.java:16)
        - waiting to lock <0x000000076ac33ce8> (a java.lang.Object)
        - locked <0x000000076ac33cd8> (a java.lang.Object)
        at DeadLockDemo$$Lambda$1/381259350.run(Unknown Source)
        at java.lang.Thread.run(Thread.java:748)

Found 1 deadlock.

其他工具如JConsole也可以达到排查的效果,这里建议,大家在开发的过程中把线程重新起个名字,方便排查问题。

如何避免死锁

死锁产生需要四个条件同时满足,破坏任何一个条件,就可以避免死锁产生。第一个条件是在并发条件下,访问临界区域下必须的,因此不做考虑。

这里不得不提一下“银行家算法”,也是解决共享资源分配避免死锁的一种方案。推荐一篇博客,https://blog.csdn.net/qq_36260974/article/details/84404369 供大家参考。

上一篇 下一篇

猜你喜欢

热点阅读