一、入題
ReentrantLock是Java並發包中互斥鎖,它有公平鎖和非公平鎖兩種實現方式,以lock()為例,其使用方式為:
ReentrantLock takeLock = new ReentrantLock();
// 獲取鎖
takeLock.lock();
try {
// 業務邏輯
} finally {
// 釋放鎖
takeLock.unlock();
}
那么,ReentrantLock內部是如何實現鎖的呢?接下來我們就以JDK1.7中的ReentrantLock的lock()為例詳細研究下。
二、ReentrantLock類的結構
ReentrantLock類實現了Lock和java.io.Serializable接口,其內部有一個實現鎖功能的關鍵成員變量Sync類型的sync,定義如下:
/** Synchronizer providing all implementation mechanics */ private final Sync sync;
而這個Sync是繼承了AbstractQueuedSynchronizer的內部抽象類,主要由它負責實現鎖的功能。關於AbstractQueuedSynchronizer我們會在以后詳細介紹,你只要知道它內部存在一個獲取鎖的等待隊列及其互斥鎖狀態下的int狀態位(0當前沒有線程持有該鎖、n存在某線程重入鎖n次)即可,該狀態位也可用於其它諸如共享鎖、信號量等功能。
Sync在ReentrantLock中有兩種實現類:NonfairSync、FairSync,正好對應了ReentrantLock的非公平鎖、公平鎖兩大類型。
三、獲取鎖主體流程
ReentrantLock的鎖功能主要是通過繼承了AbstractQueuedSynchronizer的內部類Sync來實現的,其lock()獲取鎖的主要流程如下:

首先,ReentrantLock的lock()方法會調用其內部成員變量sync的lock()方法;
其次,sync的非公平鎖NonfairSync或公平鎖FairSync實現了父類AbstractQueuedSynchronizer的lock()方法,其會調用acquire()方法;
然后,acquire()方法則在sync父類AbstractQueuedSynchronizer中實現,它只有一段代碼:
通過tryAcquire()方法試圖獲取鎖,獲取到直接返回結果,否則通過嵌套調用acquireQueued()、addWaiter()方法將請求獲取鎖的線程加入等待隊列,如果成功的話,將當前請求線程阻塞,and,over!
隊列如何實現及如何添加到隊列中以后再做詳細分析!這里只關注ReentrantLock的實現邏輯。
上述就是公平鎖、非公平鎖實現獲取鎖的主要流程,而針對每種鎖來說,其實現方式有很大差別,主要就體現在各自實現類的lock()和tryAcquire()方法中。在sync的抽象類Sync及其抽象父類AbstractQueuedSynchronizer中,lock()方法和tryAcquire()方法被定義為抽象方法或者未實現,而是由具體子類去實現:
/**
* Performs {@link Lock#lock}. The main reason for subclassing
* is to allow fast path for nonfair version.
*/
abstract void lock();
/**
* Attempts to acquire in exclusive mode. This method should query
* if the state of the object permits it to be acquired in the
* exclusive mode, and if so to acquire it.
*
* <p>This method is always invoked by the thread performing
* acquire. If this method reports failure, the acquire method
* may queue the thread, if it is not already queued, until it is
* signalled by a release from some other thread. This can be used
* to implement method {@link Lock#tryLock()}.
*
* <p>The default
* implementation throws {@link UnsupportedOperationException}.
*
* @param arg the acquire argument. This value is always the one
* passed to an acquire method, or is the value saved on entry
* to a condition wait. The value is otherwise uninterpreted
* and can represent anything you like.
* @return {@code true} if successful. Upon success, this object has
* been acquired.
* @throws IllegalMonitorStateException if acquiring would place this
* synchronizer in an illegal state. This exception must be
* thrown in a consistent fashion for synchronization to work
* correctly.
* @throws UnsupportedOperationException if exclusive mode is not supported
*/
protected boolean tryAcquire(int arg) {
throw new UnsupportedOperationException();
}
下面,我們分別研究下非公平鎖和公平鎖的實現。
四、非公平鎖NonfairSync
1、lock()方法
通過代碼可以看到,非公平鎖上來就無視等待隊列的存在而搶占鎖,通過基於CAS操作的compareAndSetState(0, 1)方法,試圖修改當前鎖的狀態,這個0表示AbstractQueuedSynchronizer內部的一種狀態,針對互斥鎖則是尚未有線程持有該鎖,而>=1則表示存在線程持有該鎖,並重入對應次數,這個上來就CAS的操作也是非公共鎖的一種體現,CAS操作成功的話,則將當前線程設置為該鎖的唯一擁有者。
搶占不成功的話,則調用父類的acquire()方法,按照上面講的,繼而會調用tryAcquire()方法,這個方法也是由最終實現類NonfairSync實現的,如下:
protected final boolean tryAcquire(int acquires) {
return nonfairTryAcquire(acquires);
}
2、tryAcquire()
而這個nonfairTryAcquire()方法實現如下:
/**
* Performs non-fair tryLock. tryAcquire is
* implemented in subclasses, but both need nonfair
* try for trylock method.
*/
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;
}
還是上來先判斷鎖的狀態,通過CAS來搶占,搶占成功,直接返回true,如果鎖的持有者線程為當前線程的話,則通過累加狀態標識重入次數。搶占不成功,或者鎖的本身持有者不是當前線程,則返回false,繼而后續通過進入等待隊列的方式排隊獲取鎖。可以通過以下簡單的圖來理解:

五、公平鎖FairSync
1、lock()
公平鎖的lock()方法就比較簡單了,直接調用acquire()方法,如下:
2、tryAcquire()
公平鎖的tryAcquire()方法也相對較簡單,如下:
/**
* Fair version of tryAcquire. Don't grant access unless
* recursive call or no waiters or is first.
*/
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;
}
當前線程會在得到當前鎖狀態為0,即沒有線程持有該鎖,並且通過!hasQueuedPredecessors()判斷當前等待隊列沒有前繼線程(也就是說,沒有比我優先級更高的線程在請求鎖了)獲取鎖的情況下,通過CAS搶占鎖,並設置自己為鎖的當前擁有者,當然,如果是重入的話,和非公平鎖處理一樣,通過累加狀態位標記重入次數。
而一旦等待隊列中有等待者,或當前線程搶占鎖失敗,則它會乖乖的進入等待隊列排隊等待。公平鎖的實現大致如下:

六、默認實現
ReentrantLock的默認實現為非公平鎖,如下:
當然,你也可以通過另外一個構造方法指定鎖的實現方式,如下:
七、其它
即便是公平鎖,如果通過不帶超時時間限制的tryLock()的方式獲取鎖的話,它也是不公平的,因為其內部調用的是sync.nonfairTryAcquire()方法,無論搶到與否,都會同步返回。如下:
public boolean tryLock() {
return sync.nonfairTryAcquire(1);
}
但是帶有超時時間限制的tryLock(long timeout, TimeUnit unit)方法則不一樣,還是會遵循公平或非公平的原則的,如下:
public boolean tryLock(long timeout, TimeUnit unit)
throws InterruptedException {
return sync.tryAcquireNanos(1, unit.toNanos(timeout));
}
其它流程都比較簡單,讀者可自行翻閱Java源碼查看!
