死锁和死锁代码实现

死锁概念

什么是死锁

死锁(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

相关推荐
洛卡卡了1 小时前
面试官问限流降级,我项目根本没做过,咋办?
后端·面试·架构
落叶的悲哀2 小时前
面试问题11
java·数据库·面试
拾光拾趣录3 小时前
🔥99%人只知WebP小,第3个特性却翻车?💥
前端·面试
Sawtone3 小时前
[前端] 面试官:Babel = 比巴卜,想吃了是吧?👿一文速通 Babel 基础知识点,全文干货,干净不废话👋
前端·面试
阿慧勇闯大前端3 小时前
最近面试问了很多次的ES6的新特性-Symbol是干啥的?
前端·面试
ZzMemory3 小时前
媒体查询:搞定响应式设计的万能利器
前端·css·面试
江湖十年4 小时前
万字长文:彻底掌握 Go 1.23 中的迭代器——使用篇
后端·面试·go
前端小巷子5 小时前
Vue 2深入 keep-alive
前端·vue.js·面试
CF14年老兵5 小时前
LocalStorage vs SessionStorage vs Cookies:浏览器数据存储终极指南
前端·javascript·面试