死锁和死锁代码实现

死锁概念

什么是死锁

死锁(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 小时前
【穿越Effective C++】条款14:在资源管理类中小心copying行为——RAII类的拷贝语义设计
c++·面试
沐怡旸17 小时前
【底层机制】ART虚拟机深度解析:Android运行时的架构革命
android·面试
阿登林21 小时前
Vue面试项目经验分享:如何专业展示技术能力与解决问题
vue.js·经验分享·面试
Java水解21 小时前
Java基础------真实大厂面试题汇总(含答案)
java·后端·面试
ANGLAL1 天前
25.Spring Boot 启动流程深度解析:从run()到自动配置
java·开发语言·面试
晴殇i1 天前
DOM嵌套关系全解析:前端必备的4大判断方法与性能优化实战
前端·javascript·面试
007php0071 天前
某游戏大厂的常用面试问题解析:Netty 与 NIO
java·数据库·游戏·面试·职场和发展·性能优化·nio
nju_spy1 天前
力扣每日一题(四)线段树 + 树状数组 + 差分
数据结构·python·算法·leetcode·面试·线段树·笔试
零雲1 天前
java面试:有了解过kafka架构吗,可以详细讲一讲吗
java·面试·kafka
HalukiSan1 天前
多线程异常、MQ、Kafka(八股)
面试·kafka