什么是死锁,产生死锁的原因及必要条件
什么是死锁?
所谓死锁,是指多个进程在运行过程中因争夺资源而造成的一种僵局,当进程处于这种僵持状态时,若无外力作用,它们都将无法再向前推进。 因此我们举个例子来描述,如果此时有一个线程A,按照先锁a再获得锁b的的顺序获得锁,而在此同时又有另外一个线程B,按照先锁b再锁a的顺序获得锁。如下图所示:
产生死锁的原因?
可归结为如下两点:
a. 竞争资源
系统中的资源可以分为两类:
可剥夺资源,是指某进程在获得这类资源后,该资源可以再被其他进程或系统剥夺,CPU和主存均属于可剥夺性资源;
另一类资源是不可剥夺资源,当系统把这类资源分配给某进程后,再不能强行收回,只能在进程用完后自行释放,如磁带机、打印机等。
产生死锁中的竞争资源之一指的是竞争不可剥夺资源(例如:系统中只有一台打印机,可供进程P1使用,假定P1已占用了打印机,若P2继续要求打印机打印将阻塞)
产生死锁中的竞争资源另外一种资源指的是竞争临时资源(临时资源包括硬件中断、信号、消息、缓冲区内的消息等),通常消息通信顺序进行不当,则会产生死锁
b. 进程间推进顺序非法
- 若P1保持了资源R1,P2保持了资源R2,系统处于不安全状态,因为这两个进程再向前推进,便可能发生死锁
- 例如,当P1运行到P1:Request(R2)时,将因R2已被P2占用而阻塞;当P2运行到P2:Request(R1)时,也将因R1已被P1占用而阻塞,于是发生进程死锁
死锁产生的4个必要条件?
产生死锁的必要条件:
- 互斥条件:进程要求对所分配的资源进行排它性控制,即在一段时间内某资源仅为一进程所占用。
- 请求和保持条件:当进程因请求资源而阻塞时,对已获得的资源保持不放。
- 不剥夺条件:进程已获得的资源在未使用完之前,不能剥夺,只能在使用完时由自己释放。
- 环路等待条件:在发生死锁时,必然存在一个进程–资源的环形链。
解决死锁的基本方法
预防死锁:
- 资源一次性分配:一次性分配所有资源,这样就不会再有请求了:(破坏请求条件)
- 只要有一个资源得不到分配,也不给这个进程分配其他的资源:(破坏请保持条件)
- 可剥夺资源:即当某进程获得了部分资源,但得不到其它资源,则释放已占有的资源(破坏不可剥夺条件)
- 资源有序分配法:系统给每类资源赋予一个编号,每一个进程按编号递增的顺序请求资源,释放则相反(破坏环路等待条件)
1、以确定的顺序获得锁
如果必须获取多个锁,那么在设计的时候需要充分考虑不同线程之前获得锁的顺序。按照上面的例子,两个线程获得锁的时序图如下:
如果此时把获得锁的时序改成:
那么死锁就永远不会发生。 针对两个特定的锁,开发者可以尝试按照锁对象的hashCode值大小的顺序,分别获得两个锁,这样锁总是会以特定的顺序获得锁,那么死锁也不会发生。问题变得更加复杂一些,如果此时有多个线程,都在竞争不同的锁,简单按照锁对象的hashCode进行排序(单纯按照hashCode顺序排序会出现“环路等待”),可能就无法满足要求了,这个时候开发者可以使用银行家算法,所有的锁都按照特定的顺序获取,同样可以防止死锁的发生,该算法在这里就不再赘述了,有兴趣的可以自行了解一下。
2、超时放弃
当使用synchronized关键词提供的内置锁时,只要线程没有获得锁,那么就会永远等待下去,然而Lock接口提供了boolean tryLock(long time, TimeUnit unit) throws InterruptedException方法,该方法可以按照固定时长等待锁,因此线程可以在获取锁超时以后,主动释放之前已经获得的所有的锁。通过这种方式,也可以很有效地避免死锁。 还是按照之前的例子,时序图如下:
避免死锁:
- 预防死锁的几种策略,会严重地损害系统性能。因此在避免死锁时,要施加较弱的限制,从而获得 较满意的系统性能。由于在避免死锁的策略中,允许进程动态地申请资源。因而,系统在进行资源分配之前预先计算资源分配的安全性。若此次分配不会导致系统进入不安全的状态,则将资源分配给进程;否则,进程等待。其中最具有代表性的避免死锁算法是银行家算法。
- 银行家算法:首先需要定义状态和安全状态的概念。系统的状态是当前给进程分配的资源情况。因此,状态包含两个向量Resource(系统中每种资源的总量)和Available(未分配给进程的每种资源的总量)及两个矩阵Claim(表示进程对资源的需求)和Allocation(表示当前分配给进程的资源)。安全状态是指至少有一个资源分配序列不会导致死锁。当进程请求一组资源时,假设同意该请求,从而改变了系统的状态,然后确定其结果是否还处于安全状态。如果是,同意这个请求;如果不是,阻塞该进程知道同意该请求后系统状态仍然是安全的。
检测死锁
- 首先为每个进程和每个资源指定一个唯一的号码;
- 然后建立资源分配表和进程等待表。
解除死锁:
当发现有进程死锁后,便应立即把它从死锁状态中解脱出来,常采用的方法有:
- 剥夺资源:从其它进程剥夺足够数量的资源给死锁进程,以解除死锁状态;
- 撤消进程:可以直接撤消死锁进程或撤消代价最小的进程,直至有足够的资源可用,死锁状态.消除为止;所谓代价是指优先级、运行代价、进程的重要性和价值等。
死锁检测
1、Jstack命令
jstack是java虚拟机自带的一种堆栈跟踪工具。jstack用于打印出给定的java进程ID或core file或远程调试服务的Java堆栈信息。 Jstack工具可以用于生成java虚拟机当前时刻的线程快照。线程快照是当前java虚拟机内每一条线程正在执行的方法堆栈的集合,生成线程快照的主要目的是定位线程出现长时间停顿的原因,如线程间死锁、死循环、请求外部资源导致的长时间等待等。 线程出现停顿的时候通过jstack来查看各个线程的调用堆栈,就可以知道没有响应的线程到底在后台做什么事情,或者等待什么资源。
2、JConsole工具
Jconsole是JDK自带的监控工具,在JDK/bin目录下可以找到。它用于连接正在运行的本地或者远程的JVM,对运行在Java应用程序的资源消耗和性能进行监控,并画出大量的图表,提供强大的可视化界面。而且本身占用的服务器内存很小,甚至可以说几乎不消耗。
什么是死锁,产生死锁的原因及必要条件相关推荐
- 什么是死锁,产生的原因,防止死锁的办法
什么是死锁? 操作系统中有若干进程并发执行,它们不断申请.使用.释放系统资源,虽然系统的进程协调.通信机构会对它们进行控制,但也可能出现若干进程都相互等待对方释放资源才能继续运行,否则就阻塞的情况.此 ...
- 死锁与活锁的原因 与解决方法(附加“饿死”)
死锁与活锁的原因 与解决方法(附加"饿死") 参考文章: (1)死锁与活锁的原因 与解决方法(附加"饿死") (2)https://www.cnblogs.co ...
- 死锁面试题(什么是死锁,产生死锁的原因及必要条件)
什么是死锁? 所谓死锁,是指多个进程在运行过程中因争夺资源而造成的一种僵局,当进程处于这种僵持状态时,若无外力作用,它们都将无法再向前推进. 因此我们举个例子来描述,如果此时有一个线程A,按照先锁a再 ...
- 【操作系统】什么是死锁,以及死锁产生的原因和必要条件
一.什么是死锁? 所谓死锁,就是在两个或多个并发进程中,如果每个进程持有某种资源而又都等待着别的进程释放它或它们现在保持着的资源,否则就不能向前推进,此时每个进程都占用了一定的资源但又都不能向前推进, ...
- 死锁产生的原因和必要条件详解
3.5 产生死锁的原因和必要条件 在多道程序系统中,虽借助于多个进程的并发执行,改善了系统的资源利用率,提高了系统的吞吐量,但可能发生一种危险--死锁. 死锁(deadlock): 是指多个进程在运行 ...
- java避免活锁.死锁的解决,死锁 活锁 饥饿 出现原因及解决方案
文章目录 死锁 概念 死锁示例 为什么会出现死锁呢? 如何解决死锁呢? 解决死锁代码实现 活锁 概念 活锁示例: 如何解决活锁呢? 饥饿 概念 如何解决饥饿呢? 死锁 概念 死锁:一组互相竞争资源的线 ...
- 什么是死锁?死锁产生的四个必要条件?如何避免与预防死锁?
一:什么是死锁 死锁是指多个进程因竞争资源而造成的一种僵局(互相等待),若无外力作用,这些进程都将无法向前推进.例如,在某一个计算机系统中只有一台打印机和一台输入 设备,进程P1正占用输入设备,同时又 ...
- java 分析java死锁_Java死锁示例–如何分析死锁情况
java 分析java死锁 死锁是两个线程或多个线程永远被阻塞的编程情况,这种情况发生在至少两个线程和两个或更多资源的情况下. 在这里,我编写了一个简单的程序,它将导致死锁情况,然后我们将看到如何对其 ...
- 查看mysql数据库的死锁日志_【MySQL】mysql死锁以及死锁日志分析
1.死锁的概念 死锁:死锁一般是事务相互等待对方资源,最后形成环路造成的. 对于死锁,数据库处理方法:牺牲一个连接,保证另外一个连接成功执行. 发生死锁会返回ERROR:1213 错误提示,大部分的死 ...
最新文章
- android 跳转到应用市场
- 劣质代码评析——《写给大家看的C语言书(第2版)》附录B之21点程序(一)
- oracle convertobject,oracle.sql進行轉換。TIMESTAMPLTZ@71d9d55b Java時間戳
- python软件是哪个国家的品牌_有哪些好用的软件被国人误认为是外国研发的?
- python正则匹配html标签_Python正则获取、过滤或者替换HTML标签的方法
- 漫画:为什么程序员没有女友?
- Oracle存储过程及调用
- Oracle分区表之创建维护分区表索引的详细步骤
- Python中的浅复制(shallow copy)和深复制(deep copy)
- 计算机科学与技术在哪里上课,计算机科学与技术在职研究生可以异地上课吗?...
- 普通类创建获取session 方式_Springboot系列之RestApi中获取枚举类属性的几种方式...
- mysql数据的持久化_一起做个简单的数据库(五):持久化存储
- 各大浏览器的最小字体与默认字体
- 二级c语言编程题库100题,计算机二级C语言编程题库100题(70页)-原创力文档
- Mac环境配置MySQL(详细)
- 【二级等保】二级等保怎么做?价格怎么样?贵吗?
- c语言选择结构程序设计实验总结,C语言程序设计,选择结构程序设计实验
- unity算法-斜抛运动(变种)
- 听风辨器,神功护体——IT运维人员的九阳神功(中)
- 查看Ubuntu下的U盘
热门文章
- 微软 Office2021 横空出世 赶紧安装 Office Tool Plus v8.14.2
- Python,燃气火焰检测主要步骤!
- 【AHK】打开网络连接/打开wifi列表/打开蓝牙列表
- python元组特点_python元组的优势有哪些
- ByteBuf使用实例
- yylabel 加载html,YYKit是个好东西-YYLabel实现一个文本多个点击事件
- linux ora 00911,ORA-00911: 无效字符
- oracle异常 无效的字符,Oracle“ORA-00911: 无效字符”解决方式
- js 终止 forEach 循环
- 使用lrz压缩上传图片,后台使用java