1. 程式人生 > >執行緒死鎖問題

執行緒死鎖問題

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>


  (2)死鎖類內部示範


<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、附:


  死鎖預防的缺點:如果都要等到資源齊全時候才能開始執行,就會大大降低系統執行的效率,如果有幾個資源就執行幾個資源,效率就會提升。

  系統效率:指系統的資源是否全部利用上,利用率高則效率高;利用率低則效率低。

  系統開銷:需要額外做一些判斷或處理操作,從而增加了系統的工作量,這樣叫做增加了系統開銷。