執行緒死鎖問題
1、引言
5個哲學家的故事:
5個哲學家去吃飯,菜飯都上齊了,筷子也上了,但是一人只有一隻筷子,每個人,先思考一會,把筷子借給別人,然後,別人吃完了,自己再吃。但是假如這5個人都餓了,他們就會拿起自己的筷子,而筷子只有一隻,大家都在等待這個別人放下那一隻筷子,然後好拿過來吃飯,而沒有任何一個人願意先放下筷子,所以,就出現了死鎖。
所以,死鎖就是兩個執行緒都掌握著另一個執行緒下一步需要訪問的資源,而兩個執行緒卻都不願意放棄自己手中的資源而導致的執行緒阻塞。
2、死鎖示例
程式碼詳解放註釋中:
(1)建立兩個鎖物件
<span style="font-size:18px;">public class MyLock {
//首先,創造出我的兩個鎖,就是創造兩個任意物件,是我的a鎖和b鎖
public static final Object objA = new Object();
public static final Object objB = new Object();
}</span>
<span style="font-size:18px;">public class DieLock extends Thread { //定義標記 private boolean flag; //構造方法傳入標記值 public DieLock(boolean flag) { this.flag = flag; } //重寫run方法 @Override public void run() { if (flag) { synchronized (MyLock.objA) { System.out.println("true -- objA");//d1執行到這裡,接下來該訪問b鎖,但是b鎖在d2的手裡,d2接下來該訪問 //a鎖,但是a鎖在d1的手裡,然後兩個都不想放鎖,誰也執行不了,就形成了死鎖。--stop synchronized (MyLock.objB) { //d1 System.out.println("true -- objB"); } } } else { synchronized (MyLock.objB) { System.out.println("false -- objB");//d2 synchronized (MyLock.objA) { //d2 System.out.println("false -- objA"); } } } } }</span>
(3)測試類
<span style="font-size:18px;">public class DieLockDemo { //測試類
public static void main(String[] args) {
//建立物件
DieLock d1 = new DieLock(true);
DieLock d2 = new DieLock(false);
//start()方法內部會自動呼叫run方法
d1.start();
d2.start();
}
}</span>
由於d1和d2都在等待對方所握有的資源,而雙方都不選擇主動放棄,所以就形成了死鎖。
3、死鎖的發生條件
互斥條件:一個資源每次只能被一個程序使用。
請求與保持條件:一個程序因請求資源而阻塞時,對已獲得的資源保持不放。
不剝奪條件:程序已獲得的資源,在末使用完之前,不能強行剝奪。
迴圈等待條件:若干程序之間形成一種頭尾相接的迴圈等待資源關係。
4、死鎖的解決辦法
首先看一個程序的五態圖:
等待資源的狀態就是執行緒的阻塞狀態,作業系統中解決死鎖的辦法有很多:
死鎖預防
破壞導致死鎖必要條件中的任意一個就可以預防死鎖。例如,要求使用者申請資源時一次性申請所需要的全部資源,這就破壞了保持和等待條件;將資源分層,得到上一層資源後,才能夠申請下一層資源,它破壞了環路等待條件。預防通常會降低系統的效率。
死鎖避免
避免是指程序在每次申請資源時判斷這些操作是否安全,例如,使用銀行家演算法。死鎖避免演算法的執行會增加系統的開銷。
預防死鎖的幾種策略,會嚴重地損害系統性能。因此在避免死鎖時,要施加較弱的限制,從而獲得 較滿意的系統性能。由於在避免死鎖的策略中,允許程序動態地申請資源。因而,系統在進行資源分配之前預先計算資源分配的安全性。若此次分配不會導致系統進入不安全狀態,則將資源分配給程序;否則,程序等待。最具有代表性的避免死鎖演算法是銀行家演算法。
死鎖檢測
死鎖預防和避免都是事前措施,而死鎖的檢測則是判斷系統是否處於死鎖狀態,如果是,則執行死鎖解除策略。這需要首先為每個程序和每個資源指定一個唯一的號碼;然後建立資源分配表和程序等待表。
死鎖解除
這是與死鎖檢測結合使用的,它使用的方式就是剝奪。即將某程序所擁有的資源強行收回,分配給其他的程序。當發現有程序死鎖後,便應立即把它從死鎖狀態中解脫出來,常採用的方法有:
剝奪資源:從其它程序剝奪足夠數量的資源給死鎖程序,以解除死鎖狀態;
撤消程序:可以直接撤消死鎖程序或撤消代價最小的程序,直至有足夠的資源可用,死鎖狀態.消除為止;所謂代價是指優先順序、執行代價、程序的重要性和價值等。
5、附:
死鎖預防的缺點:如果都要等到資源齊全時候才能開始執行,就會大大降低系統執行的效率,如果有幾個資源就執行幾個資源,效率就會提升。
系統效率:指系統的資源是否全部利用上,利用率高則效率高;利用率低則效率低。
系統開銷:需要額外做一些判斷或處理操作,從而增加了系統的工作量,這樣叫做增加了系統開銷。