重入鎖死與死鎖和嵌套管程鎖死非常相似。鎖 和讀寫鎖兩篇文章中都有涉及到重入鎖死的問題。
當(dāng)一個(gè)線程重新獲取鎖,讀寫鎖或其他不可重入的同步器時(shí),就可能發(fā)生重入鎖死。可重入的意思是線程可以重復(fù)獲得它已經(jīng)持有的鎖。Java 的 synchronized 塊是可重入的。因此下面的代碼是沒問題的:
(譯者注:這里提到的鎖都是指的不可重入的鎖實(shí)現(xiàn),并不是 Java 類庫中的 Lock 與 ReadWriteLock 類)
public class Reentrant{
public synchronized outer(){
inner();
}
public synchronized inner(){
//do something
}
}
注意 outer()和 inner()都聲明為 synchronized,這在 Java 中這相當(dāng)于 synchronized(this)塊(譯者注:這里兩個(gè)方法是實(shí)例方法,synchronized 的實(shí)例方法相當(dāng)于在 this 上加鎖,如果是 static 方法,則不然,更多閱讀:哪個(gè)對(duì)象才是鎖?)。如果某個(gè)線程調(diào)用了 outer(),outer()中的 inner()調(diào)用是沒問題的,因?yàn)閮蓚€(gè)方法都是在同一個(gè)管程對(duì)象(即 this)上同步的。如果一個(gè)線程持有某個(gè)管程對(duì)象上的鎖,那么它就有權(quán)訪問所有在該管程對(duì)象上同步的塊。這就叫可重入。若線程已經(jīng)持有鎖,那么它就可以重復(fù)訪問所有使用該鎖的代碼塊。
下面這個(gè)鎖的實(shí)現(xiàn)是不可重入的:
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();
}
}
如果一個(gè)線程在兩次調(diào)用 lock()間沒有調(diào)用 unlock()方法,那么第二次調(diào)用 lock()就會(huì)被阻塞,這就出現(xiàn)了重入鎖死。
避免重入鎖死有兩個(gè)選擇:
至于哪個(gè)選擇最適合你的項(xiàng)目,得視具體情況而定。可重入鎖通常沒有不可重入鎖那么好的表現(xiàn),而且實(shí)現(xiàn)起來復(fù)雜,但這些情況在你的項(xiàng)目中也許算不上什么問題。無論你的項(xiàng)目用鎖來實(shí)現(xiàn)方便還是不用鎖方便,可重入特性都需要根據(jù)具體問題具體分析。