死锁是什么?死锁的字节码指令了解?

用幽默浅显的言语来说死锁

半生:我已经拿到了机考的第一名,就差笔试第一名了

小一:我已经拿到了笔试的第一名,就差机考第一名了

面试官:我很看好你俩,继续"干", 同时拿到2个的第一名才能拿到offer,进入我XX大厂

半生:小一,你的笔试第一名,让我可好?

小一:做梦,我还要你的机考第一名呢!

半生:就你那水平,zz

小一:WTF,来干一架

半生:来呀,who怕who

于是:死锁产生了,狭路相逢勇者胜,电脑死机了。

什么是死锁?死锁的产生条件是什么?

1.死锁是指两个或多个线程互相等待对方释放所持有的资源,从而导致进程无法继续执行的一种情况。具体来说,死锁发生时线程会进入一个永久等待的状态,无法继续执行并最终导致程序无响应或崩溃。

2.产生死锁的条件,通常被称为死锁的四个必要条件,包括:

  1. 互斥条件(Mutual Exclusion):至少有一个资源被多个线程独占,也就是说一个资源同时只能被一个线程占用。
  2. 请求与保持条件(Hold and Wait):线程已经持有了至少一个资源,并且在等待获取其他线程占有的资源。
  3. 不可剥夺条件(No Preemption):已经获得的资源不能被其他线程抢占,只能由占有它的线程显示地释放。
  4. 循环等待条件(Circular Wait):多个线程形成一个循环等待的等待链,即每个线程都在等待下一个线程所持有的资源。

只有当上述四个条件同时满足时,死锁才可能发生。

下面上一段代码(有问题的代码,考考你们的眼力跟基本功)

 public static void main(String[] args) {final Object resource1 = new Object();final Object resource2 = new Object();Thread thread1 = new Thread(() -> {synchronized (resource1) {System.out.println("Thread 1:锁住offer1");}try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}synchronized (resource2) {System.out.println("Thread 1:锁住offer2");}});Thread thread2 = new Thread(() -> {synchronized (resource2) {System.out.println("Thread 2:锁住offer2");}try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}synchronized (resource1) {System.out.println("Thread 2:锁住offer1");}});thread1.start();thread2.start();}

为什么这2个线程都锁不住这个offer?

7c7be128d11d4408a42624aab68a8cfe.png

肥水不流外人田,既然你们都锁不住这个offer,就让我来~

public static void main(String[] args) {final Object resource1 = new Object();final Object resource2 = new Object();Thread thread1 = new Thread(() -> {synchronized (resource1) {System.out.println("半生:锁住了机考第一名");try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}synchronized (resource2) {System.out.println("半生:笔试第一名");}}});Thread thread2 = new Thread(() -> {synchronized (resource2) {System.out.println("小一:锁住了笔试第一名");try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}synchronized (resource1) {System.out.println("小一:锁住机考第一名");}}});thread1.start();thread2.start();}

6187c605ae9847b1b2d39a5eccaab3af.png

又是你俩,干啥呢,死锁了呀~offer不止一个呀,就不能友好相处,快乐的玩耍同时都拿到offer么

让我来looklook一下字节码指令是怎么去执行的

1. 先使用javac -encoding UTF-8 X.java, 来生成class文件

2. javap -verbose X.class 反编译

3.从反编译的指令来看,这里应该是操作系统或者jvm虚拟机检查到了这是个死锁,强制中断了,在使用synchronized作为锁的时候,我们知道是有monitorenter monitorexit 这一对指令的,但是这里就没有看到

4. 下载了个idea的插件jclasslib 来查看,看字节码指令是否一致

5.可以看到这里是有这一对锁指令的,这里稍微解释下上写字节码指令的含义

0 aload_0:加载索引为0的引用到操作数栈,通常用于加载实例方法的隐式参数,即this。1 dup:复制栈顶的元素,并将复制后的值重新压入栈顶。2 astore_2:将栈顶的引用类型数值存储到局部变量表的索引为2的位置。3 monitorenter:进入同步块前获取锁。4 getstatic #3 <java/lang/System.out : Ljava/io/PrintStream;>:获取静态字段System.out的值,即标准输出流PrintStream对象。7 ldc #12 <小一:锁住了笔试第一名>:将常量池中索引为12的String类型常量加载到操作数栈。9 invokevirtual #5 <java/io/PrintStream.println : (Ljava/lang/String;)V>:执行PrintStream对象的println方法,其中参数为栈顶的String类型常量。12 ldc2_w #13 <1000>:将常量池中索引为13的long类型常量加载到操作数栈。15 invokestatic #15 <java/lang/Thread.sleep : (J)V>:执行Thread类的静态方法sleep,其中参数为栈顶的long类型常量。18 goto 33 (+15):无条件跳转到字节码指令33,即跳过下方的指令。21 astore_3:将栈顶的引用类型数值存储到局部变量表的索引为3的位置。22 getstatic #3 <java/lang/System.out : Ljava/io/PrintStream;>:获取静态字段System.out的值。25 ldc #17 <小一:被中断,释放笔试资源>:将常量池中索引为17的String类型常量加载到操作数栈。27 invokevirtual #5 <java/io/PrintStream.println : (Ljava/lang/String;)V>:执行PrintStream对象的println方法,其中参数为栈顶的String类型常量。30 aload_2:加载局部变量表中索引为2的引用类型数值到操作数栈。31 monitorexit:退出同步块,释放锁。32 return:返回void类型的值,并结束当前方法。33 aload_1:加载局部变量表中索引为1的引用类型数值到操作数栈。34 dup:复制栈顶的元素,并将复制后的值重新压入栈顶。35 astore_3:将栈顶的引用类型数值存储到局部变量表的索引为3的位置。

这里的指令

第9 invokevirtual #5 <java/io/PrintStream.println : (Ljava/lang/String;)V>:执行PrintStream对象的println方法,其中参数为栈顶的String类型常量。执行了catch中的打印日志,说明被执行中断了,后面goto 33 跳到33行的指令

6.此外我另外写了同步方法,来看看

从这里看出,它是有加锁的,第20行多了一个monitorexit,这就是防止异常强制释放锁,也就是synchronized能自动释放锁的保障

于是:解决死锁的方式来了~

退一步想阔天空,你好我好大家好

public static void main(String[] args) {final Object resource1 = new Object();final Object resource2 = new Object();Thread thread1 = new Thread(() -> {synchronized (resource1) {System.out.println("半生:获得了机考第一名");try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}synchronized (resource2) {System.out.println("半生:获得了笔试第一名");}}});Thread thread2 = new Thread(() -> {synchronized (resource1) {System.out.println("小一:获得了笔试第一名");try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}synchronized (resource2) {System.out.println("小一:获得了机考第一名");}}});thread1.start();thread2.start();}

85cc84572eba4e8b85376390faadb889.png

只要稍微改下获取资源的顺序,半生跟小一就分别都获取了机考,笔试第一名,都收到了XX大厂offer

打破死锁的方式有多种,只要四个死锁的必要条件去其一就可以了

常用的有以下几种常见的方式可以用来解决死锁问题

  1. 避免循环等待:通过对资源加锁的顺序进行规定,以避免线程之间互相等待对方所持有的资源。可以通过排序或编号等方式来约定资源的获取顺序,从而避免循环等待。

  2. 破坏请求与保持条件:允许线程在请求资源时一次性获取所有需要的资源,或者在获取某个资源时释放已经占有的资源。这样可以避免一个线程持有一个资源而等待另一个资源被释放的情况。

  3. 使用资源剥夺:当一个线程请求资源时,如果资源已经被其他线程占有,则可以暂时剥夺其他线程对该资源的锁定,以满足当前线程的需求。被剥夺的线程可以等待一段时间后再重新申请资源。

  4. 使用超时机制:在获取锁资源时设置一个超时时间,在规定时间内无法获取到资源则放弃获取,释放已占有的资源,然后重新尝试。

  5. 死锁检测和恢复:通过检测系统中的死锁情况,对存在死锁的线程进行恢复或终止。常见的死锁检测算法包括资源分配图算法和银行家算法。

需要注意的是,不同的解决方式适用于不同的场景和问题,选择合适的方式需要根据具体情况进行评估。另外,预防死锁问题是更好的做法。在设计和实现时,尽量避免存在可能导致死锁的条件,从根本上杜绝死锁问题的发生。

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

算法训练 第一周

一、合并两个有序数组 本题给出了两个整数数组nums1和nums2&#xff0c;这两个数组均是非递减排列&#xff0c;要求我们将这两个数组合并成一个非递减排列的数组。题目中还要求我们把合并完的数组存储在nums1中&#xff0c;并且为了存储两个数组中全部的数据&#xff0c;nums1中…

签到系统怎么设计

背景 相信签到系统大家都有接触过&#xff0c;更多的是使用。但是有思考过这种系统是怎么设计的吗&#xff1f;比方说我统计一下每个月中每天的签到情况&#xff0c;怎么设计呢&#xff1f;今天一篇文章告诉你。 首先&#xff0c;我们熟悉的思维是&#xff1a;我设计一个数据…

[SSM]MyBatisPlus进阶

三、进阶篇 3.1映射 3.1.1自动映射规则 表名和实体类名映射 -> 表名user 实体类名User字段名和实体类属性名映射 -> 字段名name 实体类属性名name字段名下划线命名方式和实体类属性驼峰命名方式映射 -> 字段名 user_email 实体类属性名 userEmail 开启驼峰命名 m…

设计模式之适配器与装饰器

目录 适配器模式 简介 角色 使用 优缺点 使用场景 装饰器模式 简介 优缺点 模式结构 使用 使用场景 适配器模式 简介 允许将不兼容的对象包装成一个适配器类&#xff0c;使得其他类可以通过适配器类与原始对象进行交互&#xff0c;从而提高兼容性 角色 目标角色…

vite+vue3+element-plus

vitevue3element-plus 1.开始 npm create vitelatest app -- --template vuenpm installlnpm run dev2.引入element-ui npm install element-plus修改main.js import ElementPlus from element-plus import element-plus/dist/index.css createApp(App).use(ElementPlus).m…

BlueStore BlueFS rocksdb 关联性梳理

Tag: ceph 12.2.4 BlueStore空间初始化 BlueStore磁盘空间管理 总述 OSD挂载目录基于文件系统管理&#xff0c;Slow、WAL、DB空间区域基于裸盘管理&#xff1b;Slow区域&#xff1a;此类空间主要用于存储对象数据&#xff0c;由BlueStore管理&#xff0c;其中分配于BlueFS空…

AI篇-chatgpt基本用法(文心一言也适用)

目录 &#xff08;1&#xff09;基本规则 &#xff08;2&#xff09;例子1-文章摘要 &#xff08;3&#xff09;例子2-代码生成 &#xff08;4&#xff09;文心一言链接 &#xff08;1&#xff09;基本规则 相比于搜索引擎&#xff0c;ChatGPT的优势在于其高效的想法关联和…

MyBatisPlus之DQL编程控制

&#x1f40c;个人主页&#xff1a; &#x1f40c; 叶落闲庭 &#x1f4a8;我的专栏&#xff1a;&#x1f4a8; c语言 数据结构 javaEE 操作系统 石可破也&#xff0c;而不可夺坚&#xff1b;丹可磨也&#xff0c;而不可夺赤。 MyBatisPlus之DQL编程控制 一、 条件查询方式&…

Spring项目配置

1.创建项目 2.修改编码格式为UTF-8 3.检查或配置代码⾃动补全功能 4.检查或配置⾃动导包 5.检查或配置Maven&#xff0c;可以⽤国内仓库镜像 6.idea识别Maven项⽬&#xff1a;在Notifications视图中会提⽰Load Maven Project&#xff0c;点击即可。 7.开启热部署 a.确认 pom.x…

EasyPOI处理excel、CSV导入导出

1 简介 使用POI在导出导出excel、导出csv、word时代码有点过于繁琐&#xff0c;好消息是近两年在开发市场上流行一种简化POI开发的类库&#xff1a;easyPOI。从名称上就能发现就是为了简化开发。 能干什么&#xff1f; Excel的快速导入导出,Excel模板导出,Word模板导出,可以…

无涯教程-JavaScript - SECOND函数

描述 SECOND函数返回时间值的秒数。第二个数字以0(零)到59之间的整数形式给出。 语法 SECOND (serial_number)争论 Argument描述Required/OptionalSerial_number 您想找到包含秒数的时间。 时间可以输入为- 引号内的文本字符串(如" 6:45 PM") 十进制数(如0.7812…

LCD驱动电路IC简述

Panel 模块驱动图示 1.Panel内部驱动 2.驱动原理框图 2.1.1 TCON(Timing Controller):时序控制器。主要功能为数据的转换及时序控制信号生成。 2.2.2 Gate控制信号工作时序 OE1 &#xff08;output enable&#xff09;:输出控制使能信号。OE2&#xff08;Multi Level Gate)&…

数字化新零售平台系统提供商,门店商品信息智慧管理-亿发进销存

传统的批发零售业务模式正面临着市场需求变化的冲击。用户日益注重个性化、便捷性和体验感&#xff0c;新兴的新零售模式迅速崛起&#xff0c;改变了传统的零售格局。如何在保持传统业务的基础上&#xff0c;变革发展&#xff0c;成为了业界亟需解决的问题。 在这一背景下&…

AP51656 LED车灯电源驱动IC 兼容替代PT4115 PT4205 PWM和线性调光

产品描述 AP51656是一款连续电感电流导通模式的降压恒流源 用于驱动一颗或多颗串联LED 输入电压范围从 5V 到 60V&#xff0c;输出电流 可达 1.5A 。根据不同的输入电压和 外部器件&#xff0c; 可以驱动高达数十瓦的 LED。 内置功率开关&#xff0c;采用高端电流采样设置 …

Docker的数据管理(持久化存储)

文章目录 一、概述二、数据卷三、数据卷容器四、端口映射五、容器互联&#xff08;使用centos镜像&#xff09;总结 一、概述 管理 Docker 容器中数据主要有两种方式&#xff1a;数据卷&#xff08;Data Volumes&#xff09;和数据卷容器&#xff08;DataVolumes Containers&a…

Spark 环境安装与案例演示

Spark 环境安装 一、准备工作 1、hadoop成功安装 2、防火墙关闭 二、解压安装 1、上传 spark 安装包到/tools 目录&#xff0c;进入 tools 下&#xff0c;执行如下命令&#xff1a; tar -zxvf spark-2.1.0-bin-hadoop2.7.tgz -C /training/由于 Spark 的脚本命令和 Hadoop…

Astro建站教程:安装nodejs,npm下载Astro,安装扩展

下载Nodejs LTS版&#xff1a;https://nodejs.org/en 安装步骤全默认即可&#xff0c;安装路径可以根据自己的爱好更改在桌面右键打开cmd或powershell&#xff0c;输入node -v和npm -v测试是否安装成功 浏览器打开https://docs.astro.build/en/install/auto/ 复制里面的npm cre…

OB Cloud助力泡泡玛特打造新一代分布式抽盒机系统

作为中国潮玩行业的领先者&#xff0c;泡泡玛特凭借 MOLLY、DIMOO、SKULLPANDA 等爆款 IP&#xff0c;以及线上线下全渠道营销收获了千万年轻人的喜爱&#xff0c;会员数达到 2600 多万。2022 年&#xff0c;泡泡玛特实现 46.2 亿元营收&#xff0c;其中线上渠道营收占比 41.8%…

找redis大key工具rdb_bigkeys

github官网 https://github.com/weiyanwei412/rdb_bigkeys 在centos下安装go [roothadoop102 rdb_bigkeys-master]# wget https://dl.google.com/go/go1.13.5.linux-amd64.tar.gz [roothadoop102 rdb_bigkeys-master]# tar -zxf go1.13.5.linux-amd64.tar.gz -C /usr/local将g…

【开发问题系列】CSV转Excel

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:kuan 的首页,持续学…