死锁的产生及解决

死锁的概念:多个线程因竞争资源而导致进程处于一直挂起的状态;

“死锁”产生的四种情景:

  1. 单线程重复申请锁。
    如果同一个线程先后两次调用lock,在第二次调用时,由于锁已经被占用,该线程会挂起等待别的线程释放锁,然而锁被自己占用,该进程又挂起没有机会释放锁,因此就永远处于挂起等待状态,造成死锁。

  2. 双线程多锁申请
    例如两个线程A和B,线程A获得了锁1,线程B获得了锁2,这时线程A试图调用lock获得锁2,结果是需要挂起等待线程B释放锁2,而这时线程B也调用lock试图去获得锁1,结果是挂起等待线程A释放锁1,于是线程A B永远处于挂起状态

  3. 忘记释放锁
    则该进程执行完后是带着锁被挂起

  4. 环形锁申请
    看过这样一个例子,五个人围在一个桌子上吃饭,每个人必须先拿起左手边的筷子,然后再拿起右手边的筷子,才能吃饭(共五双筷子),这样,五个人都必须等待它下一个人放下筷子,它才能拿到右手边的筷子吃饭,都处于等待状态

产生“死锁”的必要条件:

  • 互斥条件:就是说多个线程不能使用同一资源;
  • 非剥夺条件:就是说所有线程的优先级都是相等的,不能在别的线程没有释放资源的情况下(该线程主动释放),夺走其占有的资源;
  • 循环等待条件:存在一种进程资源的循环等待链,链中的每一个进程已获得的资源同时被链中的下一个资源请求;
  • 请求和保持条件:进程已经保持了至少一个资源,但又提出了新的资源请求,而该资源 已被其他进程占有,此时请求进程被阻塞,但对自己已获得的资源保持不放。

解决“死锁”的方法:
其实解决死锁的方法就是打破死锁产生的四个必要条件

  1. 打破互斥:让多个线程能够内存共享
  2. 打破非剥夺:给线程定制一个优先级,当优先级高的线程所需要的资源被其他线程占用时,其他线程释放资源,优先级高的线程获得资源
  3. 打破循环等待:只要检测到自己所需要的资源被其他线程占用,即释放自己占用的资源或则等待一段时间后释放
  4. 打破请求和保持:与打破循环等待一样,当检测资源别其他线程占用时,立即释放自己的资源或则等待一点时间后释放

    如何避免“死锁”:

    1. 加锁顺序(线程按照一定的顺序加锁)
      当多个线程需要相同的一些锁,但是按照不同的顺序加锁,死锁就很容易发生。如果能确保所有的线程都是按照相同的顺序获得锁,那么死锁就不会发生;如果一个线程需要一些锁,那么它必须按照确定的顺序获取锁。它只有获得了从顺序上排在前面的锁之后,才能获取后面的锁。
      按照顺序加锁是一种有效的死锁预防机制。但是,这种方式需要你事先知道所有可能会用到的锁(译者注:并对这些锁做适当的排序),但总有些时候是无法预知的。

    2. 加锁时限(线程尝试获取锁的时候加上一定的时限,超过时限 则放弃对该锁的请求,并释放自己占有的锁)
      另外一个可以避免死锁的方法是在尝试获取锁的时候加一个超时时间,这也就意味着在尝试获取锁的过程中若超过了这个时限该线程则放弃对该锁请求。若一个线程没有在给定的时限内成功获得所有需要的锁,则会进行回退并释放所有已经获得的锁,然后等待一段随机的时间再重试。这段随机的等待时间让其它线程有机会尝试获取相同的这些锁,并且让该应用在没有获得锁的时候可以继续运行(译者注:加锁超时后可以先继续运行干点其它事情,再回头来重复之前加锁的逻辑)。

    3. 死锁检测
      它主要是针对那些不可能实现按序加锁并且锁超时也不可行的场景,每当一个线程获得了锁,会在线程和锁相关的数据结构中(map、graph等等)将其记下。除此之外,每当有线程请求锁,也需要记录在这个数据结构中。

那么当检测出死锁时,这些线程该做些什么呢?

一个可行的做法是释放所有锁,回退,并且等待一段随机的时间后重试。这个和简单的加锁超时类似,不一样的是只有死锁已经发生了才回退,而不会是因为加锁的请求超时了。虽然有回退和等待,但是如果有大量的线程竞争同一批锁,它们还是会重复地死锁(编者注:原因同超时类似,不能从根本上减轻竞争)。

一个更好的方案是给这些线程设置优先级,让一个(或几个)线程回退,剩下的线程就像没发生死锁一样继续保持着它们需要的锁。如果赋予这些线程的优先级是固定不变的,同一批线程总是会拥有更高的优先级。为避免这个问题,可以在死锁发生的时候设置随机的优先级。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值