死锁

为了线程安全,我们在需要的是会使用”独占锁“,但过多的锁定也会有麻烦。多个线程因为竞争资源相互等待而造成的僵局,我们称为死锁。若无外力作用,这些进程将都无法推进。在死锁中,至少有两个线程被挂起,并等待对方解除锁定。

我们先看一个小例子:在一个平面上有很多方块,有一些星星在这上面移动。基本规则就是:每个方块只能有一个星星。

(图1)

移动过程如下图,小黑想从a2方块移动到a3方块。这时小黑得占用a2位置,当a3位置为空时跳过去。

(图2)

当想移动的目标位置被其他星星占着的时候,就等其他星星移走后再移动过去。如下图小绿,会等到小黑移走后再移动到a2。

(图3)

但当小黑想移动的目标位置是b2的时候就悲剧了,固执的星星小黑和小绿将相互等待对方移走,直到永远。

(图4)

可能会出现更复杂的情况,小黑在等待小红移走,小红在等待小蓝移走,小蓝在等待小绿移走,小绿在等待小黑移走。这样僵持着!

(图5)

或更更复杂的情况(脑补)。。。

产生死锁的条件

产生死锁必须同时满足以下四个条件,只要其中任一条件不成立,死锁就不会发生。

  • 互斥条件:进程要求对所分配的资源进行排他性控制,即在一段时间内某资源仅为一个进程所占有。此时若有其他进程请求该资源,则请求进程只能等待。对应我们例子就是,每个方块只能容的下一个星星。
  • 不剥夺条件:进程所获得的资源在未使用完毕之前,不能被其他进程强行夺走,即只能由获得该资源的进程自己来释放(只能是主动释放)。对应我们的例子就是,星星只能等待目标位置星星自己走,而不能把它推下方块。
  • 请求和保持条件:进程已经保持了至少一个资源,但又提出了新的资源请求,而该资源已被其他进程占有,此时请求进程被阻塞,但对自己已获得的资源保持不放。对应我们的例子就是,星星得占着一个方块,然后找目标方块。
  • 循环等待条件:存在一种进程资源的循环等待链,链中每一个进程已获得的资源同时被链中下一个进程所请求。

预防死锁

从我们的例子出发,我们能想到的方法有:
1. 让星星只能按顺序跳,例如规定的顺序是a0...an...b1...bn...c1...cn。当然,有能力的星星可以跨越着跳,例如从a0到c1,但不能违背顺序逆着来。当到想回头的时候,就必须先下了方块(释放锁)再从头开始。
2. 当星星想移动的目标位置被其他星星占着的时候,就等其他星星移走后再移动过去。这是星星的移动规则,我们可以在这里加个时限,当等待的时间超过时限,就运行星星“休息”,星星就先下方块(释放锁),休息一段时间后再继续。
3. 如果星星的移动线路是比较简单的,例如每次启动只移动5步,则可以采用预定的方法。星星开始移动的时候就锁定所有将移动的方块。
4. 改变星星的基本移动方法,例如从a0->a1,移动过程改成,先下方块a0(释放资源),然后再到a1上。
5. 在4的基础上改进,每次都要下方块比较不方便,所以我们改成,当需要等待移动目标方块上星星移走的时候再先下方块。 
6. 找个管理者,当发现锁死的时候,把这些固执的星星都叫下方块。让每个星星随机等一段时间再继续。
第1种方案:按照顺序加锁是一种有效的死锁预防机制。但是,这种方式需要你事先知道所有可能会用到的锁,但总有些时候是无法预知的。基本思想就是破坏产生死锁的必要条件——循环等待条件。
第2种方案:是在尝试获取锁的时候加一个超时时间,这也就意味着在尝试获取锁的过程中若超过了这个时限该线程则放弃对该锁请求。若一个线程没有在给定的时限内成功获得所有需要的锁,则会进行回退并释放所有已经获得的锁,然后等待一段随机的时间再重试。这段随机的等待时间让其它线程有机会尝试获取相同的这些锁,并且让该线程在没有获得锁的时候可以继续运行(加锁超时后可以先继续运行干点其它事情,再回头来重复之前加锁的逻辑)。这算是一种预防,没破坏死锁的必要条件。且,如果多个线程同时请求几个资源的时候,因为等待的时间有一样,容易出现重复尝试,始终得不到锁。

第3种方案:这种方案比较暴力,杜绝了死锁。但如果一个线程需要很多资源的时候,很浪费。且容易出现,因为所需的某一两种资源不能满足而不给分配资源。

第4、5种方案:这种方案破坏产生死锁的必要条件——请求和保持条件。但并不是什么情况下都能这么用。

第6种方案:这个就是死锁检测,当发现死锁的时候进行处理。

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

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

C# 多线程系列(五)的更多相关文章

  1. java多线程系列(五)---synchronized ReentrantLock volatile Atomic 原理分析

    java多线程系列(五)---synchronized ReentrantLock volatile Atomic 原理分析 前言:如有不正确的地方,还望指正. 目录 认识cpu.核心与线程 java ...

  2. java多线程系列五、并发容器

    一.ConcurrentHashMap 1.为什么要使用ConcurrentHashMap 在多线程环境下,使用HashMap进行put操作会引起死循环,导致CPU利用率接近100%,HashMap在 ...

  3. Java多线程系列五——列表类

    参考资料: http://xxgblog.com/2016/04/02/traverse-list-thread-safe/ 一些列表类及其特性  类 线程安全 Iterator 特性 说明 Vect ...

  4. 【Java多线程系列五】列表类

    一些列表类及其特性  类 线程安全 Iterator 特性 说明 Vector 是 fail-fast 内部方法用synchronized修饰,因此执行效率较低 1. 线程安全的列表类并不意味着调用它 ...

  5. (Java多线程系列五)守护线程

    守护线程 什么是守护线程 Java中有两种线程,一种是用户线程,一种是守护线程. 当进程不存在或主线程停止,守护线程也会自动停止. class DaemonThread extends Thread ...

  6. Java多线程系列目录(共43篇)

    最近,在研究Java多线程的内容目录,将其内容逐步整理并发布. (一) 基础篇 01. Java多线程系列--“基础篇”01之 基本概念 02. Java多线程系列--“基础篇”02之 常用的实现多线 ...

  7. java多线程系列(一)

    java多线程技能 前言:本系列将从零开始讲解java多线程相关的技术,内容参考于<java多线程核心技术>与<java并发编程实战>等相关资料,希望站在巨人的肩膀上,再通过我 ...

  8. java多线程系列(二)

    对象变量的并发访问 前言:本系列将从零开始讲解java多线程相关的技术,内容参考于<java多线程核心技术>与<java并发编程实战>等相关资料,希望站在巨人的肩膀上,再通过我 ...

  9. java多线程系列(三)---等待通知机制

    等待通知机制 前言:本系列将从零开始讲解java多线程相关的技术,内容参考于<java多线程核心技术>与<java并发编程实战>等相关资料,希望站在巨人的肩膀上,再通过我的理解 ...

  10. java多线程系列(四)---Lock的使用

    Lock的使用 前言:本系列将从零开始讲解java多线程相关的技术,内容参考于<java多线程核心技术>与<java并发编程实战>等相关资料,希望站在巨人的肩膀上,再通过我的理 ...

随机推荐

  1. Java Web学习总结(29)——Java Web中的Filter和Interceptor比较

    1. 背景 在设计web应用的时候,用户登录/注册是必不可少的功能,对用户登录信息进行验证的方法也是多种多样,大致可以认为如下模式:前端验证+后台验证.根据笔者的经验,一般会在前端进行一些例如是否输入 ...

  2. Maven学习总结(29)——Maven项目的pom.xml中log4j2配置

        <dependency>         <groupId>org.apache.logging.log4j</groupId>         <a ...

  3. HDU 1254 条件过程复杂的寻找最短路

    这里一看就是找箱子到终点的最短路 一开始还傻傻的以为人的位置给的很没有意思- -,然后果然错了 没过多久想明白了错误,因为你推箱子并不是你想去哪里推就能去哪推的,首先得考虑人能否过的去,因为可能人被箱 ...

  4. codevs4343 找回密码

    题目描述 Description jrMz 很喜欢动漫<叛逆的鲁鲁修>(额= =不知道是不是因为他盯上了动画片里的 MM),他准备以一种神奇的方式降临<叛逆的鲁鲁修>世界,所以 ...

  5. Vim tips——Working with external commands

    A common sequence of events when editing files is to make a change and then need to test by executin ...

  6. ubuntu 图形界面搜索软件Catfish (鲶鱼)

    Catfish(鲶鱼)是一款Linux桌面图形软件,可以在桌面图形化的搜索文件. 在Ubuntu下可以用 : sudo apt-get install catfish 安装

  7. 违章查询免费api接口代码

    能够依据城市+车牌号+发动机号查询违章信息列表. 违章实体类 package org.wx.xhelper.model; /** * 违章实体类 * @author wangxw * @version ...

  8. ftk学习记(输入框篇)

    [ 声明:版权全部.欢迎转载.请勿用于商业用途. 联系信箱:feixiaoxing @163.com] 昨天讲了进度条,我们还是看看它的运行效果是怎么样的.截图例如以下, 进度条使用的情况还是比較多的 ...

  9. C++学习之继承中的访问控制

    我们通常认为一个类有两种不同的用户:普通用户 和 类的实现者.其中,普通用户编写的代码使用类的对象,这部分代码只能访问类的公有(接口)成员:实现者则负责编写类的成员和友元的代码,成员和友元既能访问类的 ...

  10. 1695 windows 2013

    1695 windows 2013  时间限制: 1 s  空间限制: 128000 KB  题目等级 : 黄金 Gold 题解  查看运行结果     题目描述 Description 话说adam ...