死锁和死锁代码实现

死锁概念

什么是死锁

死锁(Deadlock)描述的是这样一种情况:多个进程/线程同时被阻塞,它们中的一个或者全部都在等待某个资源被释放。由于进程/线程被无限期地阻塞,因此程序不可能正常终止。

产生死锁的四个必要条件是什么

  1. 互斥:资源必须处于非共享模式,即一次只有一个进程可以使用。如果另一进程申请该资源,那么必须等待直到该资源被释放为止。
  2. 占有并等待:一个进程至少应该占有一个资源,并等待另一资源,而该资源被其他进程所占有。
  3. 非抢占:资源不能被抢占。只能在持有资源的进程完成任务后,该资源才会被释放。
  4. 循环等待 :有一组等待进程 {P0, P1,..., Pn}P0 等待的资源被 P1 占有,P1 等待的资源被 P2 占有,......,Pn-1 等待的资源被 Pn 占有,Pn 等待的资源被 P0 占有。

注意 :这四个条件是产生死锁的 必要条件 ,也就是说只要系统发生死锁,这些条件必然成立,而只要上述条件之一不满足,就不会发生死锁。

解决死锁的方法

解决死锁的方法可以从多个角度去分析,一般的情况下,有预防,避免,检测和解除四种

  • 预防 是采用某种策略,限制并发进程对资源的请求,从而使得死锁的必要条件在系统执行的任何时间上都不满足。
  • 避免 则是系统在分配资源时,根据资源的使用情况提前做出预测 ,从而避免死锁的发生
  • 检测 是指系统设有专门的机构,当死锁发生时,该机构能够检测死锁的发生,并精确地确定与死锁有关的进程和资源。
  • 解除 是与检测相配套的一种措施,用于将进程从死锁状态下解脱出来

死锁的预防

只要破坏四个必要条件中的任何一个就能够预防死锁的发生。

  • 破坏第一个条件 互斥条件:使得资源是可以同时访问的,这是种简单的方法,磁盘就可以用这种方法管理,但是我们要知道,有很多资源 往往是不能同时访问的 ,所以这种做法在大多数的场合是行不通的。
  • 破坏第三个条件 非抢占:也就是说可以采用 剥夺式调度算法,但剥夺式调度方法目前一般仅适用于 主存资源和处理器资源 的分配,并不适用于所有的资源,会导致 资源利用率下降。

所以一般比较实用的 预防死锁的方法,是通过考虑破坏第二个条件和第四个条件。

  • 静态分配策略 静态分配策略可以破坏死锁产生的第二个条件(占有并等待)。所谓静态分配策略,就是指一个进程必须在执行前就申请到它所需要的全部资源,并且知道它所要的资源都得到满足之后才开始执行。进程要么占有所有的资源然后开始执行,要么不占有资源,不会出现占有一些资源等待一些资源的情况。 静态分配策略逻辑简单,实现也很容易,但这种策略 严重地降低了资源利用率,因为在每个进程所占有的资源中,有些资源是在比较靠后的执行时间里采用的,甚至有些资源是在额外的情况下才使用的,这样就可能造成一个进程占有了一些 几乎不用的资源而使其他需要该资源的进程产生等待 的情况。
  • 层次分配策略 层次分配策略破坏了产生死锁的第四个条件(循环等待)。在层次分配策略下,所有的资源被分成了多个层次,一个进程得到某一次的一个资源后,它只能再申请较高一层的资源;当一个进程要释放某层的一个资源时,必须先释放所占用的较高层的资源,按这种策略,是不可能出现循环等待链的,因为那样的话,就出现了已经申请了较高层的资源,反而去申请了较低层的资源,不符合层次分配策略。

死锁的代码实例

通过两个线程相互持有对方需要的锁资源,从而形成死锁。

java 复制代码
public class deadLock {
    private static final Object lock1 = new Object();
    private static final Object lock2 = new Object();

    public static void main(String[] args) {
        Thread thread1 = new Thread(() -> {
            synchronized (lock1){
                System.out.println("thread1 : holding lock1");
                try {
                    Thread.sleep(10);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
                System.out.println("thread1 : getting lock2 ");
                synchronized (lock2){
                    System.out.println("thread1 : holding lock1 && lock2");
                }
            }
        });

        Thread thread2 = new Thread(() -> {
            synchronized (lock2){
                System.out.println("thread2 : holding lock2");
                try {
                    Thread.sleep(10);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
                System.out.println("thread2 : getting lock1");
                synchronized (lock1){
                    System.out.println("thread2 : holding lock2 && lock1");
                }
            }
        });

        thread1.start();
        thread2.start();
    }
}

死锁链(多个锁串起来)

java 复制代码
public class DeadlockChain {
    private static final Object Lock1 = new Object();
    private static final Object Lock2 = new Object();
    private static final Object Lock3 = new Object();

    public static void main(String[] args) {
        Thread t1 = new Thread(() -> {
            synchronized (Lock1) {
                System.out.println("T1 locked Lock1");
                try { Thread.sleep(100); } catch (Exception e) {}
                synchronized (Lock2) {
                    System.out.println("T1 locked Lock2");
                }
            }
        });

        Thread t2 = new Thread(() -> {
            synchronized (Lock2) {
                System.out.println("T2 locked Lock2");
                try { Thread.sleep(100); } catch (Exception e) {}
                synchronized (Lock3) {
                    System.out.println("T2 locked Lock3");
                }
            }
        });

        Thread t3 = new Thread(() -> {
            synchronized (Lock3) {
                System.out.println("T3 locked Lock3");
                try { Thread.sleep(100); } catch (Exception e) {}
                synchronized (Lock1) {
                    System.out.println("T3 locked Lock1");
                }
            }
        });

        t1.start();
        t2.start();
        t3.start();
    }
}

内容参考:javaguide

相关推荐
测试涛叔16 小时前
金三银四软件测试面试题(800道)
软件测试·面试·职场和发展
C雨后彩虹17 小时前
计算疫情扩散时间
java·数据结构·算法·华为·面试
蒹葭玉树18 小时前
【C++上岸】C++常见面试题目--操作系统篇(第二十八期)
linux·c++·面试
多米Domi01121 小时前
0x3f 第48天 面向实习的八股背诵第五天 + 堆一题 背了JUC的题,java.util.Concurrency
开发语言·数据结构·python·算法·leetcode·面试
win x1 天前
JavaSE(基础)高频面试点及 知识点
java·面试·职场和发展
编程彩机1 天前
互联网大厂Java面试:从分布式缓存到消息队列的技术场景解析
java·redis·面试·kafka·消息队列·微服务架构·分布式缓存
xiaoye-duck1 天前
C++ string 底层原理深度解析 + 模拟实现(上)——面试 / 开发都适用
c++·面试·stl
小旭95271 天前
Java 反射详解
java·开发语言·jvm·面试·intellij-idea
indexsunny1 天前
互联网大厂Java求职面试实战:Spring Boot微服务与Kafka消息队列应用解析
java·数据库·spring boot·微服务·面试·kafka·jpa
源代码•宸1 天前
Golang面试题库(Interface、GMP)
开发语言·经验分享·后端·面试·golang·gmp·调度过程