死锁的讲解

2023-11-15

目录

1. 死锁定义

2. 死锁产生原因

3. 如何解决死锁问题


1. 死锁定义

死锁是指两个或两个以上的进程在执⾏过程中,由于竞争资源或者由于彼此通信⽽造成的⼀种阻塞的现象,若⽆外⼒作⽤,它们都将⽆法推进下去。(也就是两个线程拥有锁的情况下,⼜在尝试获取对⽅锁,从⽽造成程序⼀直阻塞的情况。)

2. 死锁产生原因

形成死锁主要由以下 4 个因素造成的:
        ① 互斥条件 ⼀个资源只能被⼀个线程占有,当这个资源被占⽤之后其他线程就只能等待。
        ② 不可被剥夺条件 当⼀个线程不主动释放资源时,此资源⼀直被拥有线程占有,其他线程不能得到此资源。
        ③ 请求并持有条件 线程已经拥有了⼀个资源之后,又尝试请求新的资源。
        ④ 环路等待条件 产⽣死锁⼀定是发⽣了线程资源环形链。
形成死锁,四个因素缺一不可。

3. 如何解决死锁问题

打破产生死锁的一个或者多个条件即可。

        ① 互斥条件 改变不了。
        ② 不可被剥夺条件 改变不了。
        ③ 请求并持有条件 可以改变(人为控制)。
        ④ 环路等待条件 可以改变(人为控制)。
public class UnDeadLock {
    public static void main(String[] args) {
        Object lockA = new Object();
        Object lockB = new Object();

        Thread t1 = new Thread(() -> {
            synchronized (lockA) {
                System.out.println("线程1:得到锁A");
                //业务代码
                try {
                    TimeUnit.SECONDS.sleep(1);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                synchronized (lockB) {
                    System.out.println("线程1:得到锁B");
                    //业务代码
                    System.out.println("线程1:释放锁B");
                }
                System.out.println("线程1:释放锁A");
            }
        },"线程1");
        t1.start();

        Thread t2 = new Thread(() -> {
            synchronized (lockB) {
                System.out.println("线程2:得到锁B");
                //业务代码
                try {
                    TimeUnit.SECONDS.sleep(1);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                synchronized (lockA) {
                    System.out.println("线程2:得到锁A");
                    //业务代码
                    System.out.println("线程2:释放锁A");
                }
                System.out.println("线程2:释放锁A");
            }
        },"线程2");
        t2.start();
    }
}

输出
    线程1:得到锁A
    线程2:得到锁B
(......没有结束)

上面代码产生了死锁。解决方法:

1. 修改获取锁请求并持有条件:

解决死锁方法:破坏请求并持有条件

public class UnDeadLock {
    public static void main(String[] args) {
        Object lockA = new Object();
        Object lockB = new Object();

        Thread t1 = new Thread(() -> {
            synchronized (lockA) {
                System.out.println("线程1:得到锁A");
                //业务代码
                try {
                    TimeUnit.SECONDS.sleep(1);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
//                synchronized (lockB) {
//                    System.out.println("线程1:得到锁B");
//                    //业务代码
//                    System.out.println("线程1:释放锁B");
//                }
                System.out.println("线程1:释放锁A");
            }
        },"线程1");
        t1.start();

        Thread t2 = new Thread(() -> {
            synchronized (lockB) {
                System.out.println("线程2:得到锁B");
                //业务代码
                try {
                    TimeUnit.SECONDS.sleep(1);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
//                synchronized (lockA) {
//                    System.out.println("线程2:得到锁A");
//                    //业务代码
//                    System.out.println("线程2:释放锁A");
//                }
                System.out.println("线程2:释放锁B");
            }
        },"线程2");
        t2.start();
    }
}

输出:
    线程1:得到锁A
    线程2:得到锁B
    线程2:释放锁B
    线程1:释放锁A

 2. 修改获取锁的有序性来改变环路等待条件:

(使用顺序锁解决死锁问题)

 

 

解决死锁方法:修改获取锁的有序性来改变环路等待条件

public class UnDeadLock2 {
    public static void main(String[] args) {
        Object lockA = new Object();
        Object lockB = new Object();

        Thread t1 = new Thread(() -> {
            synchronized (lockA) {
                System.out.println("线程1:得到锁A");
                //业务代码
                try {
                    TimeUnit.SECONDS.sleep(1);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                synchronized (lockB) {
                    System.out.println("线程1:得到锁B");
                    //业务代码
                    System.out.println("线程1:释放锁B");
                }
                System.out.println("线程1:释放锁A");
            }
        },"线程1");
        t1.start();

        Thread t2 = new Thread(() -> {
            synchronized (lockA) {
                System.out.println("线程2:得到锁A");
                //业务代码
                try {
                    TimeUnit.SECONDS.sleep(1);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                synchronized (lockB) {
                    System.out.println("线程2:得到锁B");
                    //业务代码
                    System.out.println("线程2:释放锁B");
                }
                System.out.println("线程2:释放锁A");
            }
        },"线程2");
        t2.start();
    }
}

输出:
    线程1:得到锁A
    线程1:得到锁B
    线程1:释放锁B
    线程1:释放锁A
    线程2:得到锁A
    线程2:得到锁B
    线程2:释放锁B
    线程2:释放锁A

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

死锁的讲解 的相关文章

随机推荐

  • Jsvc

    Jsvc How to detach the Java daemon from the shell script Toolbox for IT Groups How to detach the Java daemon from the sh
  • 学习多线程,创建多线程的三种方式

    多线程 并发与并行 并发 两个或多个事件在同一个时间段内发生 交替执行 并行 两个或多个事件在同一个时刻发生 同时执行 进程与线程 进程 进入到内存中的程序 线程 进程中的一个执行单元 负责当前进程中程序的执行 一个进程中至少有一个线程 一
  • 教你如何在VSCode中使用markdown标记语言并转为word

    目录 准备工作 正文开始 准备工作 插件 1 安装 pandoc https pandoc org installing html Windows用户进入官网后 直接点最大的那个按钮就行了 其他操作系统找到相应的下载点 这里我就不多讲了 实
  • 【解决】IDEA默认的代码格式化快捷键是失效

    Ctrl Alt L 网易云的快捷键 关掉网易云后 IDEA格式化快捷键就可以使用了
  • markdown表格合并单元格,嵌入HTML语法

    markdown的语法并不支持表格单元格合并 但可以通过嵌入HTML来解决 例如想实现这样的单元格合并效果 网络状态指示引脚的工作状态 引脚名 引脚工作状态 所指示的网络状态 NET STATUS 慢闪 200 ms 高 1800 ms 低
  • Java Scheduled定时任务

    开启定时任务步骤流程 1 在启动类添加注解 注意 千万不要忘记 EnableScheduling 2 在具体的方法上添加定时任务注解 Scheduled cron 0 0 3 每3个小时触发一次 3 定时任务开启时间 常用的 Schedul
  • SpringBoot集成Redis来实现缓存技术方案

    为什么80 的码农都做不了架构师 gt gt gt 概述 在我们的日常项目开发过程中缓存是无处不在的 因为它可以极大的提高系统的访问速度 关于缓存的框架也种类繁多 今天主要介绍的是使用现在非常流行的NoSQL数据库 Redis 来实现我们的
  • 【VS2010学习笔记】【异常处理】general error c1010070: Failed to load and parse the manifest.

    在VS2010编程中 有时编译会遇到这样的错误 general error c1010070 Failed to load and parse the manifest 解决方法就是在解决方案中将后缀名为manifest的文件删除 再编译即
  • css 第二行的元素设置margin-top间隔

    css 第二行的元素设置margin top间隔
  • Extjs的Form表单提交方式

    Extjs的Form表单提交方式 一 直接提交 url写在表单中 var addForm new Ext FormPanel frame true url insertProject eva doType insertProject lab
  • PCIe5.0的Add-in-Card(AIC)金手指layout建议(三)

    PCIe5 0的Add in Card AIC 金手指layout建议 一 PCIe5 0的Add in Card AIC 金手指layout建议 二 前面两篇文章介绍了第一种金手指的layout建议 适用速率在32 0 GT s 以下介绍
  • 关于爬虫技术

    1 什么是爬虫 爬虫是一种自动化程序 它能够模拟人类用户访问网站的行为 从网站上抓取数据并保存到本地或者进行进一步处理 爬虫是一种非常常用的网络数据采集工具 可以用于搜索引擎 电商数据采集 舆情监测等多个领域 通过使用爬虫 可以自动化地获取
  • springboot获取nacos的服务列表、实例列表及修改实例、发布配置等

    1 通过java sdk的方式发布配置 官方文档说明 https nacos io zh cn docs sdk html https nacos io zh cn docs open api html 1 1构造ConfigService
  • Linux系统中环境变量的设置

    目录 业务描述 设置环境变量的方法 系统环境变量 指定用户环境变量 临时有效的环境变量 系统常用环境变量应用分析 PATH 环境变量 HOME 环境变量 HISTSIZE 环境变量 LOGNAME环境变量 SHELL环境变量 业务描述 Li
  • 【JAVA进阶】File类、字节流

    个人主页 个人主页 系列专栏 JAVASE基础 前言 目前的编程中 数据存储方式有很多种 包括但不限于 文件存储 将数据以文件的形式存储在磁盘上 可以使用文件读写操作进行数据的存取 数据库存储 将数据以表格的形式存储在数据库中 可以使用SQ
  • 黑群晖docker安装人人影视_在云主机上手动安装腾讯PAI面板

    本文关键字 云主机上装管理面板 在前面 我们介绍过lnmp sandstorm paas 还有黑群晖 docker管理面板 这些都是云OS上的面板扩展和APPSTACK扩展 分散在不同级别被实现 像群晖这种是OS和面板一体的 包括这里要介绍
  • line-height的使用

    line height 26px 表示行高为26px line height 120 表示行高为当前字体大小的120 line height 2 6em 表示行高为当前字体的2 6倍 带单位的行高都有继承性 其子元素继承的是计算值 如父元素
  • 计算机盲打最快要多久,电脑打字怎样做到又快又准确

    除了熟悉26个字母 我们还要熟悉键盘 熟悉键盘是根本 可以下载个金山打字通练习下很快就上手了 而本文笔者着重给大家讲解下可以帮助自己快速输入的技巧 还是要利用工具的 我们聊天的时候 有的词语如果是你常用到的 而这个词又有点长 不是成语类的
  • ctfshow-网络迷踪-新手上路 ( 使用百度搜图收集景点信息)

    ctf show 网络迷踪模块第1关 只有一座桥的图片 拿到桥的名字即可 推荐使用百度搜图 先把图片下载到本地 使用百度搜图收集图片中的景点信息 根据搜图的结果可以发现 图片的来源均指向同一个地方 三亚蜈支洲岛 接下来 百度搜索 三亚蜈支洲
  • 死锁的讲解

    目录 1 死锁定义 2 死锁产生原因 3 如何解决死锁问题 1 死锁定义 死锁是指两个或两个以上的进程在执 过程中 由于竞争资源或者由于彼此通信 造成的 种阻塞的现象 若 外 作 它们都将 法推进下去 也就是两个线程拥有锁的情况下 在尝试获