当前位置: 首页 > news >正文

什么是死锁 , 以及产生的原因详细介绍

死锁

一. 什么是死锁

指的是两个或者两个以上的线程在执行的过程中由于竞争同步锁而产生的一种阻塞现象;如果没有外力的作用,他们将无法继续执行下去,这种情况称之为死锁,

通俗的说死锁产生的原因主要是由于线程的相互等待 , 导致程序无法进行下去

二. 代码阐述

这里我们写一段代码对死锁进行描述, 阐述其中的原理

  1. LockA类 --> 设置线程

    public class LockA {public static LockA lockA = new LockA();
    }
  2. LockB类 --> 设置线程

    public class LockB {public static LockB lockB = new LockB();
    }
    
  3. DieLock类 --> 继承Runnable重写run方法

    public class DieLock implements Runnable{private boolean flag;public DieLock(boolean flag) {this.flag = flag;}@Overridepublic void run() {if (flag){synchronized (LockA.lockA){System.out.println("if...lockA");synchronized (LockB.lockB){System.out.println("if...lockB");}}}else{synchronized (LockB.lockB){System.out.println("else...lockB");synchronized (LockA.lockA){System.out.println("else...lockA");}}}}
    }
  4. Test01类 --> 实现类

    public class Test01 {public static void main(String[] args) {DieLock dieLock1 = new DieLock(true);DieLock dieLock2 = new DieLock(false);new Thread(dieLock1).start();new Thread(dieLock2).start();}
    }

在这里插入图片描述

场景描述

假设有两个线程 Thread1Thread2,它们分别通过不同的构造函数参数初始化了 DieLock 对象:

  • Thread1 初始化了 DieLock 对象,其中 flagtrue
  • Thread2 初始化了 DieLock 对象,其中 flagfalse

执行流程

  1. Thread1 执行

    • 首先获取 LockA.lockA 锁。
    • 然后尝试获取 LockB.lockB 锁。
  2. Thread2 执行

    (几乎同时或稍后):

    • 首先获取 LockB.lockB 锁(因为 flagfalse)。
    • 然后尝试获取 LockA.lockA 锁。

死锁发生

  • Thread1 已经持有 LockA.lockA 锁,并正在等待 LockB.lockB 锁。
  • Thread2 已经持有 LockB.lockB 锁,并正在等待 LockA.lockA 锁。

由于两个线程都在等待对方释放它们需要的锁,它们都将无限期地等待下去,从而导致了死锁。

在这里由于synchronized 控制的是整个代码块 , 当程序执行完毕才会释放此时占有lockA锁

synchronized (LockA.lockA){System.out.println("if...lockA");synchronized (LockB.lockB){System.out.println("if...lockB");}}

同理Thread2占有lockB锁 , 然而此时Thread1线程中LockA在等待LockB , Thread2线程中LockB 在等待LockA就会产生死锁

如果我们稍作修改 , 将Thread2 的第二层嵌套取消掉就会发现运行结果不一样了 , 死锁问题不会产生

此时Thread2在获得LockB之后运行完毕释放LockB , Thread1也能获取到LockB进而继续执行

public class DieLock implements Runnable{private boolean flag;public DieLock(boolean flag) {this.flag = flag;}@Overridepublic void run() {if (flag){synchronized (LockA.lockA){System.out.println("if...lockA");synchronized (LockB.lockB){System.out.println("if...lockB");}}}else{synchronized (LockB.lockB){System.out.println("else...lockB");}}}}
}

在这里插入图片描述

相关文章:

  • 1.6.丢弃法
  • 论文复现:Predictive Control of Networked Multiagent Systems via Cloud Computing
  • x264 编码器 CAVLC 熵编码源码分析
  • Alpine Linux 轻量级Linux 适合于 docker 容器镜像
  • 浏览器缓存:强缓存与协商缓存实现原理有哪些?
  • HTTPS请求头缺少HttpOnly和Secure属性解决方案
  • 微服务实战系列之玩转Docker(二)
  • redis基本类型和订阅
  • 数据结构之初始二叉树(2)
  • docker网络互联
  • 机器学习-20-基于交互式web应用框架streamlit的基础使用教程
  • 企业如何查看员工的上网时长和记录?如何查看公司局域网员工电脑的上网记录
  • uniapp 开发 App 对接官方更新功能
  • 【Android】基础—基本布局
  • 校验el-table中表单项
  • 《Java8实战》-第四章读书笔记(引入流Stream)
  • 【划重点】MySQL技术内幕:InnoDB存储引擎
  • angular学习第一篇-----环境搭建
  • CAP 一致性协议及应用解析
  • create-react-app做的留言板
  • idea + plantuml 画流程图
  • IE报vuex requires a Promise polyfill in this browser问题解决
  • java中具有继承关系的类及其对象初始化顺序
  • js中forEach回调同异步问题
  • mongo索引构建
  • spring学习第二天
  • win10下安装mysql5.7
  • 从输入URL到页面加载发生了什么
  • 大整数乘法-表格法
  • 当SetTimeout遇到了字符串
  • 解决iview多表头动态更改列元素发生的错误
  • 罗辑思维在全链路压测方面的实践和工作笔记
  • 浅谈Golang中select的用法
  • 深入浏览器事件循环的本质
  • 一份游戏开发学习路线
  • ​​​​​​​STM32通过SPI硬件读写W25Q64
  • ​sqlite3 --- SQLite 数据库 DB-API 2.0 接口模块​
  • ​如何使用QGIS制作三维建筑
  • # linux 中使用 visudo 命令,怎么保存退出?
  • #Datawhale AI夏令营第4期#AIGC方向 文生图 Task2
  • (1)Map集合 (2)异常机制 (3)File类 (4)I/O流
  • (2)STL算法之元素计数
  • (33)STM32——485实验笔记
  • (5)STL算法之复制
  • (大众金融)SQL server面试题(1)-总销售量最少的3个型号的车及其总销售量
  • (附源码)springboot家庭财务分析系统 毕业设计641323
  • (删)Java线程同步实现一:synchronzied和wait()/notify()
  • (转) SpringBoot:使用spring-boot-devtools进行热部署以及不生效的问题解决
  • (转)socket Aio demo
  • (转载)Linux 多线程条件变量同步
  • .bat批处理(一):@echo off
  • .naturalWidth 和naturalHeight属性,
  • .Net Attribute详解(上)-Attribute本质以及一个简单示例
  • .net core 6 使用注解自动注入实例,无需构造注入 autowrite4net
  • .net core 源码_ASP.NET Core之Identity源码学习