閱讀640 返回首頁    go 阿裏雲 go 技術社區[雲棲]


重入鎖死

重入鎖死與死鎖嵌套管程鎖死非常相似。讀寫鎖兩篇文章中都有涉及到重入鎖死的問題。

當一個線程重新獲取讀寫鎖或其他不可重入的同步器時,就可能發生重入鎖死。可重入的意思是線程可以重複獲得它已經持有的鎖。Java的synchronized塊是可重入的。因此下麵的代碼是沒問題的:

(譯者注:這裏提到的鎖都是指的不可重入的鎖實現,並不是Java類庫中的Lock與ReadWriteLock類)

public class Reentrant{
	public synchronized outer(){
		inner();
	}

	public synchronized inner(){
		//do something
	}
}

注意outer()和inner()都聲明為synchronized,這在Java中這相當於synchronized(this)塊(譯者注:這裏兩個方法是實例方法,synchronized的實例方法相當於在this上加鎖,如果是static方法,則不然,更多閱讀:哪個對象才是鎖?)。 如果某個線程調用了outer(),outer()中的inner()調用是沒問題的,因為兩個方法都是在同一個管程對象(即this)上同步的。如果一 個線程持有某個管程對象上的鎖,那麼它就有權訪問所有在該管程對象上同步的塊。這就叫可重入。若線程已經持有鎖,那麼它就可以重複訪問所有使用該鎖的代碼 塊。

下麵這個鎖的實現是不可重入的:

public class Lock{
	private boolean isLocked = false;
	public synchronized void lock()
		throws InterruptedException{
		while(isLocked){
			wait();
		}
		isLocked = true;
	}

	public synchronized void unlock(){
		isLocked = false;
		notify();
	}
}

如果一個線程在兩次調用lock()間沒有調用unlock()方法,那麼第二次調用lock()就會被阻塞,這就出現了重入鎖死。

避免重入鎖死有兩個選擇:

  1. 編寫代碼時避免再次獲取已經持有的鎖
  2. 使用可重入鎖

至於哪個選擇最適合你的項目,得視具體情況而定。可重入鎖通常沒有不可重入鎖那麼好的表現,而且實現起來複雜,但這些情況在你的項目中也許算不上什麼問題。無論你的項目用鎖來實現方便還是不用鎖方便,可重入特性都需要根據具體問題具體分析。


文章轉自 並發編程網-ifeve.com

最後更新:2017-05-22 20:04:37

  上一篇:go  線程池
  下一篇:go  多線程的代價