之前有文章說過,synchronized和ReenTrantLock都是可重入鎖,那麼什麼是可重入鎖?
可重入鎖從字面意思就比較容易理解,自己獲取了鎖以後,可以再次獲取該鎖(重入)就叫可重入鎖,同一個線程每次獲取鎖,鎖計數器都自增1,所以要等到鎖的計數器下降爲0時才能釋放鎖。
我們就以之前賣票的例子進行講解,因爲synchronized加鎖和解鎖的過程是自動進行,所以不會造成死鎖,而ReentrantLock加鎖和解鎖的過程需要手動,所以如果加鎖和釋放鎖次數不一,會導致死鎖,我們看代碼:
public class FairLocked implements Runnable {
private int seatNumber = 100;
/**
* 公平鎖實現 ReentrantLock構造方法中設置爲true:代表公平鎖
*
* 設置爲false:代表非公平鎖 默認也是非公平鎖
*
*/
/** private ReentrantLock lock = new ReentrantLock(true); */
/** private ReentrantLock lock = new ReentrantLock(false); */
private ReentrantLock lock = new ReentrantLock();
@Override
public void run() {
while (true) {
try {
lock.lock();
if (seatNumber > 0) {
Thread.sleep(100);
--seatNumber;
System.out.println(Thread.currentThread().getName() + "佔用1個座位,還剩餘 " + seatNumber + "個座位");
} else {
System.out.println(Thread.currentThread().getName() + ":不好意思,票賣完了!");
break;
}
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
/** lock.unlock(); */
}
}
}
public static void main(String[] args) {
FairLocked rlbr = new FairLocked();
Thread t1 = new Thread(rlbr, "A窗口");
Thread t2 = new Thread(rlbr, "B窗口");
t1.start();
t2.start();
}
}
那麼,可重入鎖的原理是什麼呢?
之前我們也有提到過一個詞,叫鎖計數器。重入鎖實現機制就是基於一個鎖關聯一個線程持有者和計數器,當計數器爲0時表示該鎖沒有被任何線程持有,那麼任何線程都可能獲得該鎖而調用相應的方法;當某一線程請求成功後,JVM會記下鎖的線程持有者,同時將鎖計數器置爲1;此時其它線程請求該鎖,就只能等待,而該鎖持有者卻可以再次請求鎖,同時鎖計數器會遞增,當線程退出同步代碼塊時,計數器會遞減,直至鎖計數器爲0,則釋放。
所以,如果ReentrantLock不手動釋放鎖,就會造成死鎖。