探秘死锁:原理、发生条件及解决方案

news2025/1/14 1:10:50

探秘死锁:原理、发生条件及解决方案

死锁是多线程编程中常见的一个问题,它会导致程序停止响应,进而影响系统的稳定性和性能。理解死锁的原理、发生条件以及如何预防和解决死锁是编写健壮并发程序的关键。

1. 死锁的定义

死锁是指两个或多个线程在执行过程中因争夺资源而相互等待,从而使得这几个线程都无法继续执行。死锁会导致系统资源无法被正常利用,进而影响系统的稳定性。

如上图所示死锁状态,线程 A 己经持有了资源 2,它同时还想申请资源 1,可是此时线程 B 已经持有了资源 1 ,线程 A 只能等待。

反观线程 B 持有了资源 1 ,它同时还想申请资源 2,但是资源 2 已经被线程 A 持有,线程 B 只能等待。所以线程 A 和线程 B 就因为相互等待对方已经持有的资源,而进入了死锁状态。

2. 死锁的四个必要条件

根据Coffman提出的经典死锁四个必要条件(又称Coffman条件):

  • 互斥(Mutual Exclusion):资源不能被多个线程同时使用。
  • 持有并等待(Hold and Wait):一个线程已经持有了至少一个资源,同时又在等待获取额外的资源。
  • 不可剥夺(No Preemption):线程获得的资源在使用完之前不能被强行剥夺,只能由线程自己释放。
  • 循环等待(Circular Wait):存在一个循环等待链,即每个线程都在等待下一个线程所持有的资源。

3. 死锁的示例代码

以下是一个Java示例,展示了死锁的产生:

public class DeadlockExample {
    private static final Object resource1 = new Object();
    private static final Object resource2 = new Object();

    public static void main(String[] args) {
        Thread thread1 = new Thread(() -> {
            synchronized (resource1) {
                System.out.println("Thread 1: locked resource 1");
                try { Thread.sleep(50); } catch (InterruptedException e) {}
                synchronized (resource2) {
                    System.out.println("Thread 1: locked resource 2");
                }
            }
        });

        Thread thread2 = new Thread(() -> {
            synchronized (resource2) {
                System.out.println("Thread 2: locked resource 2");
                try { Thread.sleep(50); } catch (InterruptedException e) {}
                synchronized (resource1) {
                    System.out.println("Thread 2: locked resource 1");
                }
            }
        });

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

在这个示例中,thread1首先锁住resource1,然后试图锁住resource2。与此同时,thread2首先锁住resource2,然后试图锁住resource1。这会导致两个线程相互等待,从而产生死锁。

4. 死锁的预防和避免

破坏互斥条件
  • 使资源尽量支持共享访问,例如使用读写锁来允许多个线程同时读取资源。
破坏持有并等待条件
  • 线程在开始时一次性请求所需要的所有资源,如果没有得到全部资源,则释放已获得的资源并重新请求。
  • 使用锁定机制时,可以尝试锁定时限,如果超时则释放已持有的锁。
破坏不可剥夺条件
  • 设计资源请求策略,使得可以强制抢占资源。例如,使用可重入锁(ReentrantLock)和条件变量(Condition)来支持资源的强制释放。
破坏循环等待条件
  • 为资源分配一个全局顺序,线程按照固定顺序请求资源,避免形成循环等待链。

5. 死锁检测与恢复

死锁检测
  • 系统可以定期检测资源分配图,判断是否存在循环等待。如果发现死锁,则需要进行相应的恢复操作。
死锁恢复
  • 资源抢占:强制从某个线程中剥夺资源,分配给其他需要资源的线程。
  • 回滚:回滚部分或全部死锁进程的操作,使其释放所持有的资源。
  • 终止进程:直接终止部分或全部死锁进程,从而释放资源。

示例代码中的解决方案

以下是改进后的代码,避免了死锁:

public class DeadlockFreeExample {
    private static final Object resource1 = new Object();
    private static final Object resource2 = new Object();

    public static void main(String[] args) {
        Thread thread1 = new Thread(() -> {
            synchronized (resource1) {
                System.out.println("Thread 1: locked resource 1");
                try { Thread.sleep(50); } catch (InterruptedException e) {}
                synchronized (resource2) {
                    System.out.println("Thread 1: locked resource 2");
                }
            }
        });

        Thread thread2 = new Thread(() -> {
            synchronized (resource1) { // 改变锁顺序
                System.out.println("Thread 2: locked resource 1");
                try { Thread.sleep(50); } catch (InterruptedException e) {}
                synchronized (resource2) {
                    System.out.println("Thread 2: locked resource 2");
                }
            }
        });

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

在这个改进后的例子中,我们确保了两个线程都以相同的顺序(先锁resource1,再锁resource2)来获取锁,从而避免了循环等待的条件。

结论

理解死锁的原理及其四个必要条件是预防和解决死锁问题的基础。通过合理的设计和编程技巧,可以有效地避免死锁,提高并发程序的健壮性和性能。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1691311.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

前端 CSS 经典:SVG 描边动画

1. 原理 使用 css 中的 stroke 属性,用来描述描边的样式,其中重要的属性 stroke-dasharray、stroke-dashoffset。理解了这两个属性的原理,才能理解描边动画实现的原理。 stroke-dasharray:将描边线变成虚线、其中实线和虚线部分…

NDIS小端口驱动开发(一)

在四种NDIS相关的驱动中,微型端口驱动(也经常翻译为为小端口驱动)位于驱动栈的底部,一般将它理解为NIC设备的驱动程序: 有几种类型的微型端口驱动程序类型: 无连接微型端口驱动程序用于控制无连接网络媒体 ,如以太网的…

代码随想录算法训练营第十四天(py)| 二叉树 | 递归遍历、迭代遍历、统一迭代

1 理论基础 1.1 二叉树的种类 满二叉树 只有度为0和2的节点,且度为0的节点在同一层。 深度为k,有2^k-1个节点 完全二叉树 除了最底层可能没填满,其余每层节点数都达到最大。并且最底层节点全部集中在左边。 二叉搜索树 是一个有数值…

【class14】人工智能初步之语音识别

【class14】 从本节课开始,我们将一起踏入语音识别的世界,学习这些知识点,为自己的视频匹配上字幕:1. 语音识别2. 采样率3. 创建语音识别应用4. 创建语音识别SDK客户端 人类的自然语言可分为两种形态:1.语音&#xff…

Python使用pymysql操作数据库

大家好,当涉及到与数据库进行交互和操作时,Python的pymysql库是一个常用且功能强大的选择。pymysql提供了与MySQL数据库的连接、查询、插入、更新和删除等操作的方法,使得在Python中进行数据库操作变得简单而高效。 1、安装 pymysql 库 在开…

python判断字符串是否为回文串的详细解析与实现

新书上架~👇全国包邮奥~ python实用小工具开发教程http://pythontoolsteach.com/3 欢迎关注我👆,收藏下次不迷路┗|`O′|┛ 嗷~~ 目录 一、引言:回文串的定义与背景 二、判断回文串的基本思路 示例解析 三、代码实…

LabVIEW和ZigBee无线温湿度监测

LabVIEW和ZigBee无线温湿度监测 随着物联网技术的迅速发展,温湿度数据的远程无线监测在农业大棚、仓库和其他需环境控制的场所变得日益重要。开发了一种基于LabVIEW和ZigBee技术的多区域无线温湿度监测系统。系统通过DHT11传感器收集温湿度数据,利用Zig…

【ARK Survival Evolved】方舟:生存进化一键使用服务器开服联机教程

1、进入控制面板 2、第一次购买服务器会安装游戏端,大约5分钟左右,如果长时间处于安装状态请联系客服 3、设置游戏端口 方舟生存进化的设置需要三个端口,它们用于游戏端口(必须为首选端口),查询端口&#…

html5 笔记02

目录 01 svg的基本使用 02 svg绘图 03 进程和线程 01 svg的基本使用 svg和canvas的区别: canvas: 1.canvas作为一个容器只有一个dom元素 ,内部元素无法使用dom操作 (canvas不能展开然后选择不到 svg查看元素能选中因为是通过标签控制的) 2.canvas 是配合js完成各种绘制效果 …

【学习笔记】Webpack5(Ⅱ)

Webpack 3、高级篇 3.1、提升开发体验 —— SourceMap 3.2、提升打包速度 3.2.1 HotModuleReplacement 3.2.2 OneOf 3.2.3 Include / Exclude 3.2.4 Cache 3.2.5 Thread 3.3、减少代码体积 …

iMX6ULL 嵌入式linux开发 | 4G无线广播终端实现方案介绍

现有的有线广播,如村上的大喇叭,需要布线,施工麻烦。借助现有的4G网络,传输音频流完全没问题,4G网络结合流媒体技术和MQTT消息传递实现设备间的同步推拉流。这种方案可以避免有线布线的麻烦,同时实现4G无线…

Spark在YARN上运行图解(资源调度+任务调度)及案例

前提:已经安装了spark集群,可参考上篇文章搭建:http://t.csdnimg.cn/UXBOp 一、Spark集群配置YARN 1、增加hadoop 配置文件地址 vim spark-env.sh 增加export HADOOP_CONF_DIR/usr/local/soft/hadoop-3.1.1/etc/hadoop 2、关闭虚拟内存 cd …

DMR对讲机数字协议详解

一、概述 DMR数字对讲机协议是欧洲电信标准协会在2005年4月推出的数字对讲机标准,后来又进行了多次修改。最新版本DMR数字对讲机协议是2007年12月公布的,共有四部分:第一部分为空中接口物理层和数据链路层协议,第二部分为空中接口…

【Unity AR开发插件】四、制作热更数据-AR图片识别场景

专栏 本专栏将介绍如何使用这个支持热更的AR开发插件,快速地开发AR应用。 链接: Unity开发AR系列 插件简介 通过热更技术实现动态地加载AR场景,简化了AR开发流程,让用户可更多地关注Unity场景内容的制作。 “EnvInstaller…”支…

牛客网刷题 | BC93 公务员面试

目前主要分为三个专栏,后续还会添加: 专栏如下: C语言刷题解析 C语言系列文章 我的成长经历 感谢阅读! 初来乍到,如有错误请指出,感谢! 描述 公务员面试现场打分…

【安装笔记-20240520-Windows-在 QEMU 中尝试运行 OpenWRT】

安装笔记-系列文章目录 安装笔记-20240520-Windows-在 QEMU 中尝试运行 OpenWRT 文章目录 安装笔记-系列文章目录安装笔记-20240520-Windows-在 QEMU 中尝试运行 OpenWRT 前言一、软件介绍名称:OpenWRT主页官方介绍 二、安装步骤测试版本:openwrt-23.05…

C语言在VS中使用scanf报错?

我们在使用VS时,用scanf函数,VS会报以下错误: 以下是解决方法: 来到输出窗口,复制以下语句:_CRT_SECURE_NO_WARNINGS 第一种暂时方法 1.在代码的第一行,写下:#define _CRT_SECURE_…

vuejs路由和组件系统

前端路由原理 createRouter * hash* window.addEventListener(hashChange)* 两种实现路由切换的模式:UI组件(router-link,router-view),Api(push()方法) * history * HTML5新增的API &#xff0…

2024年电工杯A题论文首发+摘要分享+问题一代码分享

问题一论文代码链接:https://pan.baidu.com/s/1kDV0DgSK3E4dv8Y6x7LExA 提取码:sxjm --来自百度网盘超级会员V5的分享 园区微电网风光储协调优化配置 摘要:园区微电网由风光发电和主电网联合为负荷供电,为了尽量提高风光电量的…

机器人运动轨迹学习——GMM/GMR算法

机器人运动轨迹学习——GMM/GMR算法 前置知识 GMM的英文全称为:Gaussian mixture model,即高斯混合模型,也就是说,它是由多个高斯模型进行混合的结果:当然,这里的混合是带有权重概念的。 一维高斯分布 GMM中…