一、阻塞/非阻塞、同步/非同步java
同步与非同步(消息通知机制):关注的是等待过程的通知方式须要本身主动询问仍是被动通知。算法
阻塞与非阻塞(等待消息通知时的状态):关注的是等待过程是否能够转变为其余非等待状态。安全
举例说明:假设我要下载一个视频框架
一、经过看下载进度条等待下载完成的结果(同步),期间不作其余事情(阻塞)异步
二、经过看下载进度条等待下载完成的结果(同步),期间去聊QQ,在聊QQ的时候不停地去看下载是否完成(非阻塞)spa
三、经过下载完成的提示音通知获得下载完成的结果(异步),期间不作其余事情(阻塞)操作系统
四、经过下载完成的提示音通知获得下载完成的结果(异步),期间去聊QQ,在聊QQ的时候不须要去看下载是否完成,由于下载完了提示音会通知我(非阻塞)线程
论这四个概念的时候必定要放在同一个层级,好比操做系统级别,框架级别,业务代码级别等,由于一个事件在不一样层级所属的性质不必定同样,只有在同一个层级,才能去讨论它的性质是同步/异步仍是阻塞/非阻塞。视频
阻塞与非阻塞并无好坏之分,有不一样的应用场景,好比在阻塞期间会屡次尝试,可是阻塞不能作其余事情,效率不高。非阻塞能作其余事情,可是也会增长线程切换的开销。blog
二、死锁
2.1 死锁的四个必要条件
死锁是指两个或两个以上的进程在执行过程当中,因为竞争资源或者因为彼此通讯而形成的一种阻塞的现象,若无外力做用,它们都将没法推动下去。此时称系统处于死锁状态或系统产生了死锁,这些永远在互相等待的进程称为死锁进程。
如下四个条件是死锁发生的必要条件,缺一不可,若是发生了死锁则下列条件必定所有知足:四个状态同时知足就是不安全状态,可是进入不安全状态并不必定会发生死锁;
1)互斥条件:指进程对所分配到的资源进行排它性使用,即在一段时间内某资源只由一个进程占用。若是此时还有其它进程请求资源,则请求者只能等待,直至占有资源的进程用毕释放。
2)请求和保持条件:指进程已经保持至少一个资源,但又提出了新的资源请求,而该资源已被其它进程占有,此时请求进程阻塞,但又对本身已得到的其它资源保持不放。
3)不剥夺条件:指进程已得到的资源,在未使用完以前,不能被剥夺,只能在使用完时由本身释放。
4)环路等待条件:指在发生死锁时,必然存在一个进程——资源的环形链,即进程集合{P0,P1,P2,···,Pn}中的P0正在等待一个P1占用的资源;P1正在等待P2占用的资源,……,Pn正在等待已被P0占用的资源。
2.2 避免死锁
避免死锁就是打破上述 四个必要条件至少一个:
(1)打破互斥条件:运通多个进程同时访问(有些资源是独占资源,例如打印机,没法共享)
(2)打破请求保持条件:预先一次性分配全部资源,若是缺乏则所有不分配。
(3)打破不剥夺条件:容许进程从资源占有者哪里夺取资源,实际上是本身已经有资源A,去申请资源B,可是没有成功,此时释放资源A分配给其余进程,也就至关于其余进程隐性抢占了资源A。
(4)打破环路等待条件:实施资源有序分配。全部资源实现编号,按照号从小到大进行分配,全部程序都是在占有小号资源的前提下才能申请大号资源,从而不会造成环路。
2.3 死锁避免算法
安全序列:安全序列{P1,P2,...,Pn}是这样组成的:若对于每个进程Pi,它须要的附加资源能够被系统中当前可用资源加上全部进程Pj当前占有资源之和所知足,则{P1,P2,...,Pn}为一个安全序列,这时系统处于安全状态,不会进入死锁状态。 ????不太懂
银行家算法:一个银行家拥有必定数量的资金,有若干个客户要贷款。每一个客户须在一开始就声明他所需贷款的总额。若该客户贷款总额不超过银行家的资金总数,银行家能够接收客户的要求。客户贷款是以每次一个资金单位(如1万RMB等)的方式进行的,客户在借满所需的所有单位款额以前可能会等待,但银行家须保证这种等待是有限的,可完成的。
对于a图的状态,按照安全序列的要求,咱们选的第一个客户应知足该客户所需的贷款小于等于银行家当前所剩余的钱款,能够看出只有C2客户能被知足:C2客户需1个资金单位,小银行家手中的2个资金单位,因而银行家把1个资金单位借C2客户,使之完成工做并归还所借的3个资金单位的钱,进入b图。同理,银行家把4个资金单位借给C3客户,使其完成工做,在c图中,只剩一个客户C1,它需7个资金单位,这时银行家有8个资金单位,因此C1也能顺利借到钱并完成工做。最后(见图d)银行家收回所有10个资金单位,保证不赔本。那麽客户序列{C1,C2,C3}就是个安全序列,按照这个序列贷款,银行家才是安全的。不然的话,若在图b状态时,银行家把手中的4个资金单位借给了C1,则出现不安全状态:这时C1,C3均不能完成工做,而银行家手中又没有钱了,系统陷入僵持局面,银行家也不能收回投资。
综上所述,银行家算法是从当前状态出发,逐个按安全序列检查各客户谁能完成其工做,而后假定其完成工做且归还所有贷款,再进而检查下一个能完成工做的客户,......。若是全部客户都能完成工做,则找到一个安全序列,银行家才是安全的。
从上面分析看出,银行家算法容许互斥条件,占有且申请条件,不可抢占条件的存在,这样,它与预防死锁的几种方法相比较,限制条件少了,资源利用程度提升了。
这是该算法的优势。其缺点是:
〈1〉这个算法要求客户数保持固定不变,这在多道程序系统中是难以作到的。
〈2〉这个算法保证全部客户在有限的时间内获得知足,但实时客户要求快速响应,因此要考虑这个因素。
〈3〉因为要寻找一个安全序列,实际上增长了系统的开销。
2.4 死锁的检测与恢复
2.4.1 死锁检测
一个简单却无效率的方法:有两个容器,一个用于保存线程正在请求的锁,一个用于保存线程已经持有的锁。每次加锁以前都会作以下检测:
1)检测当前正在请求的锁是否已经被其它线程持有,若是有,则把那些线程找出来;
2)遍历第一步中返回的线程,检查本身持有的锁是否正被其中任何一个线程请求。若是第二步返回真,表示出现了死锁。
java中的Thread类中的holdslock()方法。
2.4.2 死锁恢复
一旦在死锁检测时发现了死锁,就要消除死锁,使系统从死锁状态中恢复过来。
(1)最简单,最经常使用的方法就是进行系统的从新启动,不过这种方法代价很大,它意味着在这以前全部的进程已经完成的计算工做都将付之东流,包括参与死锁的那些进程,以及未参与死锁的进程。
(2)撤消进程,剥夺资源。终止参与死锁的进程,收回它们占有的资源,从而解除死锁。这时又分两种状况:一次性撤消参与死锁的所有进程,剥夺所有资源;或者逐步撤消参与死锁的进程,逐步收回死锁进程占有的资源。通常来讲,选择逐步撤消的进程时要按照必定的原则进行,目的是撤消那些代价最小的进程,好比按进程的优先级肯定进程的代价;考虑进程运行时的代价和与此进程相关的外部做业的代价等因素。
此外,还有进程回退策略,即让参与死锁的进程回退到没有发生死锁前某一点处,并由此点处继续执行,以求再次执行时再也不发生死锁。虽然这是个较理想的办法,可是操做起来系统开销极大,要有堆栈这样的机构记录进程的每一步变化,以便从此的回退,有时这是没法作到的。