Java多线程编程学习——03线程死锁



什么是死锁?

多个线程抢占同一资源,并请求锁定对方资源,造成恶性循环且无外力情况下无法执行下去的情况叫做死锁。

死锁产生的四个必要条件

互斥条件

线程(进程)要求对所分配的资源具有排他性,即在一段时间内某个资源被当前线程(进程)所占有,其他线程(进程)若想请求获得该资源只能等待。

不可剥夺条件

线程(进程)请求锁定某个资源未释放之前,其他线程(进程)不可抢占和剥夺该线程所持有的资源,必须等待该线程(进程)执行完成释放该资源后才可获得。

请求与保持条件

已拥有资源的线程(进程)二次请求新的资源,而该资源已被其他线程(进程)所占有,此时请求阻塞并对其原持有的资源保持不放。

循环与等待条件

存在一种请求资源得循环等待链,链中每一个线程(进程)已获得资源的同时并请求新的资源,形成闭路循环等待,造成阻塞。


死锁处理

  • 预防死锁:通过设置某些限制条件,去破坏产生死锁的四个必要条件中的一个或几个条件,来防止死锁的发生。
  • 避免死锁:在资源的动态分配过程中,用某种方法去防止系统进入不安全状态,从而避免死锁的发生。
  • 检测死锁:允许系统在运行过程中发生死锁,但可设置检测机构及时检测死锁的发生,并采取适当措施加以清除。
  • 解除死锁:当检测出死锁后,便采取适当措施将进程从死锁状态中解脱出来。

死锁预防

预防死锁是设法至少破坏产生死锁的四个必要条件之一,严格的防治死锁的出现。

破坏“互斥”条件

"互斥”条件是无法破坏的,资源的互斥本身就是对死锁的一种预防。

破坏“请求与保持”条件

一次性分配所需资源

破坏“不可剥夺”条件

如果已占有资源的线程(进程)进一步请求新的资源失败,则该线程(进程)必须释放它已持有的资源。

破坏“循环与等待”条件

按序申请资源来预防。按某一顺序申请资源,释放资源则反序释放。破坏循环等待条件。


死锁避免

有序资源分配法
  1. 必须为所有资源统一编号
  2. 同类资源必须一次申请完
  3. 不同类资源必须按顺序申请

例如:有两个进程P1和P2,有两个资源R1和R2
P1请求资源:R1、R2
P2请求资源:R1、R2
这样就破坏了环路条件,避免了死锁的发生。

银行家算法

银行家算法(Banker’s Algorithm)是一个避免死锁(Deadlock)的著名算法,是由艾兹格·迪杰斯特拉在1965年为T.H.E系统设计的一种避免死锁产生的算法。它以银行借贷系统的分配策略为基础,判断并保证系统的安全运行。流程图如下:

在这里插入图片描述
银行家算法的基本思想是分配资源之前,判断系统是否是安全的;若为是,才分配。它是最具有代表性的避免死锁的算法。
设进程i提出请求REQUEST [i],则银行家算法按如下规则进行判断。

  1. 如果REQUEST [i]<= NEED[i,j],则转(2);否则,出错。
  2. 如果REQUEST [i]<=
    AVAILABLE[i],则转(3);否则,等待。
  3. 系统试探分配资源,修改相关数据:
    AVAILABLE[i]-=REQUEST[i];//可用资源数-请求资源数
    ALLOCATION[i]+=REQUEST[i];//已分配资源数+请求资源数
    NEED[i]-=REQUEST[i];//需要资源数-请求资源数
  4. 系统执行安全性检查,如安全,则分配成立;否则试探险性分配作废,系统恢复原状,进程等待。

顺序加锁

当多个线程(进程)需要相同的一些锁,但是按照不同的顺序加锁,死锁就很容易发生。如果能确保所有的线程(进程)都是按照相同的顺序获得锁,那么死锁就不会发生。

按照顺序加锁是一种有效的死锁预防机制。但是,这种方式需要事先知道所有可能会用到的锁,但总有些时候是无法预知的,所以该种方式只适合特定场景。


限时加锁

限时加锁是线程(进程)在尝试获取锁的时候加一个限制时间,若超过这个时间则放弃对该锁请求,并回退释放所有已经获得的锁,然后等待一段随机的时间再重试

缺点

  1. 当线程(进程)数量少时,该种方式可避免死锁,但当线程(进程)数量过多,这些线程(进程)的加锁时限相同的概率就高很多,可能会导致超时后等待死循环。
  2. Java中不能对synchronized同步块设置超时时间。需要创建一个自定义锁,或使用Java5中java.util.concurrent包下的工具。

死锁检测

预防和避免死锁系统开销大且不能充分利用资源,更好的方法是不采取任何限制性措施,而是提供检测和解脱死锁的手段,这就是死锁检测和恢复。
死锁检测数据结构:

  • E是现有资源向量(existing resource vector),代码每种已存在资源的总数
  • A是可用资源向量(available resource vector),那么Ai表示当前可供使用的资源数(即没有被分配的资源)
  • C是当前分配矩阵(current allocation matrix),C的第i行代表Pi当前所持有的每一种类型资源的资源数
  • R是请求矩阵(request matrix),R的每一行代表P所需要的资源的数量

在这里插入图片描述

死锁检测步骤

  1. 寻找一个没有结束标记的进程Pi,对于它而言R矩阵的第i行向量小于或等于A。
  2. 如果找到了这样一个线程(进程),执行该线程(进程),然后将C矩阵的第i行向量加到A中,标记该线程(进程),并转到第1步
  3. 如果没有这样的线程(进程),那么算法终止
  4. 算法结束时,所有没有标记过的进程都是死锁线程(进程)。

死锁恢复

利用抢占恢复。

临时将某个资源从它的当前所属进程转移到另一个线程(进程)。 这种做法很可能需要人工干预,主要做法是否可行需取决于资源本身的特性。

利用回滚恢复

周期性的将线程(进程)的状态进行备份,当发现线程(进程)死锁后,根据备份将该线程(进程)复位到一个更早的,还没有取得所需的资源的状态,接着就把这些资源分配给其他死锁线程(进程)。

通过杀死线程(进程)恢复

最直接简单的方式就是杀死一个或若干个线程(进程)。
尽可能保证杀死的线程(进程)可以从头再来而不带来副作用。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值