關於阻塞/非阻塞、同步/非同步、死鎖

一、阻塞/非阻塞、同步/非同步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)撤消進程,剝奪資源。終止參與死鎖的進程,收回它們佔有的資源,從而解除死鎖。這時又分兩種狀況:一次性撤消參與死鎖的所有進程,剝奪所有資源;或者逐步撤消參與死鎖的進程,逐步收回死鎖進程佔有的資源。通常來講,選擇逐步撤消的進程時要按照必定的原則進行,目的是撤消那些代價最小的進程,好比按進程的優先級肯定進程的代價;考慮進程運行時的代價和與此進程相關的外部做業的代價等因素。 

    此外,還有進程回退策略,即讓參與死鎖的進程回退到沒有發生死鎖前某一點處,並由此點處繼續執行,以求再次執行時再也不發生死鎖。雖然這是個較理想的辦法,可是操做起來系統開銷極大,要有堆棧這樣的機構記錄進程的每一步變化,以便從此的回退,有時這是沒法作到的。

相關文章
相關標籤/搜索