顯式鎖ReentrantLock
與 內建鎖synchronize
不同,它並不是一種替代內建鎖的方式,而是作為一種可選擇的高階功能。
public interface Lock {
void lock();
void lockInterruptibly() throws InterruptedException;
boolean tryLock();
boolean tryLock(long time, TimeUnit unit) throws InterruptedException;
void unlock();
Condition newCondition();
}
ReentrantLock 實現了 Lock介面,意味著其具有無條件的,可中斷的,可輪詢以及定時的鎖獲取操作,所有的加鎖與解鎖必須顯式的呼叫!
2.1 公平鎖與非公平鎖
我們先來討論以下ReentrantLock高階功能之一:公平鎖與非公平鎖!
ReentrantLock 預設採用非公平鎖
public ReentrantLock() {
sync = new NonfairSync(); //此處預設是非公平鎖!
}
public ReentrantLock(boolean fair) {
sync = fair ? new FairSync() : new NonfairSync();
}
再看看公平鎖和非公平鎖的實現,兩者都是實現了Sync的靜態內部類。先看下公平鎖的核心方法:
/**
* Sync object for fair locks
*/
//公平鎖!!!!!!!
static final class FairSync extends Sync {
private static final long serialVersionUID = -3000897897090466540L;
final void lock() {
acquire(1);
}
//注意這個acquire方法是在AbstractQueuedSynchronizer中實現的!並不是公平鎖的方法!
public final void acquire(int arg) {
if (!tryAcquire(arg) && //當前執行緒是否能獲得鎖!
acquireQueued(addWaiter(Node.EXCLUSIVE), arg))//獲取不了加入到等待佇列的尾部
selfInterrupt(); //最終阻塞當前執行緒!
}
/**
* 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) { //判斷是否為0,即當前是否有執行緒正持有這個鎖!
if (!hasQueuedPredecessors() && //首先會判斷是否有執行緒正在等待,如果有等待,為保證公平性跳到最底部返回false,即試圖獲取鎖失敗!
compareAndSetState(0, acquires)) { //然後透過cas操作競爭鎖
setExclusiveOwnerThread(current);
return true;
}
}
else if (current == getExclusiveOwnerThread()) { //ok,有執行緒持有這個鎖,就判斷一下是否是本執行緒持有這個鎖,ok,持有,重入!
int nextc = c + acquires;
if (nextc < 0)
throw new Error("Maximum lock count exceeded");
setState(nextc); //更改鎖計數資訊
return true;
}
return false; // 都不是,直接返回false
}
}
再看下非公平鎖的
static final class NonfairSync extends Sync {
final void lock() {
// 和公平鎖相比,這裡會直接先進行一次CAS,成功就返回了
if (compareAndSetState(0, 1))
setExclusiveOwnerThread(Thread.currentThread());
else
acquire(1);
}
// AbstractQueuedSynchronizer.acquire(int arg)
public final void acquire(int arg) {
if (!tryAcquire(arg) &&
acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
selfInterrupt();
}
protected final boolean tryAcquire(int acquires) {
return nonfairTryAcquire(acquires);
}
}
/**
* 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;
}
總結
- 非公平鎖在呼叫 lock 後,首先就會呼叫 CAS 進行一次搶鎖,如果這個時候恰巧鎖沒有被佔用,那麼直接就獲取到鎖返回了。
- 非公平鎖在 CAS 失敗後,和公平鎖一樣都會進入到 tryAcquire 方法,在 tryAcquire 方法中,如果發現鎖這個時候被釋放了(state == 0),非公平鎖會直接 CAS 搶鎖,但是公平鎖會判斷等待佇列是否有執行緒處於等待狀態,如果有則不去搶鎖,乖乖排到後面。
本作品採用《CC 協議》,轉載必須註明作者和本文連結