類圖
ReentrantLock相關類圖:
AbstractOwnableSynchronizer類保持和獲取獨佔線程。
AbstractQueuedSynchronizer,繼承自AbstractOwnableSynchronizer,簡稱AQS,基於FIFO(First Input First Output)隊列的實現。以虛擬隊列的方式管理線程的鎖獲取與鎖釋放,以及各種情況下的線程中斷。提供了默認的同步實現,但是獲取鎖和釋放鎖的實現定義爲抽象方法,由子類實現。目的是使開發人員可以自由定義獲取鎖以及釋放鎖的方式。
Sync是ReentrantLock的內部抽象類,繼承自AbstractQueuedSynchronizer,實現了簡單的獲取鎖和釋放鎖。NonfairSync和FairSync分別表示“非公平鎖”和“公平鎖”,都繼承於Sync,並且都是ReentrantLock的內部類。
ReentrantLock實現了Lock接口的lock-unlock方法,根據fair參數決定使用NonfairSync還是FairSync。
AQS
ReentrantLock實現的前提就是AbstractQueuedSynchronizer,簡稱AQS,是java.util.concurrent的核心,CountDownLatch、FutureTask、Semaphore、ReentrantLock等都有一個內部類是這個抽象類的子類。
Node
Node是AQS的內部類,是對每一個訪問同步代碼的線程的封裝。不僅包括了需要同步的線程,而且也包含了每個線程的狀態,比如等待解除阻塞,等待條件喚醒,已經被取消等等。同時Node還關聯了前驅和後繼,即prev和next。
多個Node連接起來成爲了虛擬隊列(因爲不存在真正的隊列容器將每個元素裝起來所以說是虛擬的,我把它稱爲release隊列,意思是等待釋放),其實就是一個有頭有尾的雙向鏈表結構:
state
是AQS的一個成員變量,用來記錄鎖的持有情況:
沒有線程持有鎖的時候,state爲0。
當某個線程獲取鎖時,state的值增加,具體增加多少開發人員可自定義,默認爲1,表示該鎖正在被一個線程佔有。
當某個已經佔用鎖的線程再次獲取到鎖時,state再增長,此爲重入鎖。
當佔有鎖的線程釋放鎖時,state也要減去當初佔有時傳入的值,默認爲1。
多個線程競爭鎖的時候,state必須通過CAS進行設置,這樣才能保證鎖只能有一個線程持有。
Sync
NonfairSync和FairSync分別表示“非公平鎖”和“公平鎖”,都繼承於Sync,並且都是ReentrantLock的內部類。
我們來看NonfairSync獲取鎖的代碼:
protected final boolean tryAcquire(int acquires) {
return nonfairTryAcquire(acquires);
}
final boolean nonfairTryAcquire(int acquires) {
final Thread current = Thread.currentThread();
int c = getState();
if (c == 0) {
if (compareAndSetState(0, acquires)) {
setExclusiveOwnerThread(current);
return true;
}
}
else if (current == getExclusiveOwnerThread()) {
int nextc = c + acquires;
if (nextc < 0) // overflow
throw new Error("Maximum lock count exceeded");
setState(nextc);
return true;
}
return false;
}
還有FairSync獲取鎖的代碼:
protected final boolean tryAcquire(int acquires) {
final Thread current = Thread.currentThread();
int c = getState();
if (c == 0) {
if (!hasQueuedPredecessors() &&
compareAndSetState(0, acquires)) {
setExclusiveOwnerThread(current);
return true;
}
}
else if (current == getExclusiveOwnerThread()) {
int nextc = c + acquires;
if (nextc < 0)
throw new Error("Maximum lock count exceeded");
setState(nextc);
return true;
}
return false;
}
其實差別就在於NonfairSync獲取鎖時比FairSync中少了一個判斷!hasQueuedPredecessors()
,hasQueuedPredecessors()中判斷了是否存在等待隊列,導致公平鎖和非公平鎖的差異如下:
公平鎖:公平鎖講究先來先到,線程在獲取鎖時,如果這個鎖的等待隊列中已經有線程在等待,那麼當前線程就會進入等待隊列中。
非公平鎖:不管是否有等待隊列,如果可以獲取鎖,則立刻佔有鎖對象。
lock()與unlock()
lock()
流程圖(圖中的Node0和Node1在源代碼中不存在,是爲了方便說明清楚才添加的別稱):
unlock()
流程圖:
參考:
1.ReentrantLock實現原理深入探究
2.ReentrantLock的lock-unlock流程詳解
3.輕鬆學習java可重入鎖(ReentrantLock)的實現原理
4.ReentrantLock解析
5.深度解析Java8 – AbstractQueuedSynchronizer的實現分析(上)
6.ReentrantLock(重入鎖)以及公平性