ReentrantLock,可重入鎖,是一種遞歸無阻塞的同步機制。它能夠等同於 synchronized 的使用,可是 ReentrantLock 提供了比 synchronized 更強大、靈活的鎖機制,能夠減小死鎖發生的機率。java
一個可重入的互斥鎖定 Lock,它具備與使用 synchronized 方法和語句所訪問的隱式監視器鎖定相同的一些基本行爲和語義,但功能更強大。c#
ReentrantLock 將由最近成功得到鎖定,而且尚未釋放該鎖定的線程所擁有。安全
當鎖定沒有被另外一個線程所擁有時,調用 lock 的線程將成功獲取該鎖定並返回。多線程
若是當前線程已經擁有該鎖定,此方法將當即返回。可使用 #isHeldByCurrentThread() 和 #getHoldCount() 方法來檢查此狀況是否發生。ide
ReentrantLock 還提供了公平鎖和非公平鎖的選擇,經過構造方法接受一個可選的 fair 參數(默認非公平鎖):當設置爲 true 時,表示公平鎖;不然爲非公平鎖。性能
公平鎖與非公平鎖的區別在於,公平鎖的鎖獲取是有順序的。可是公平鎖的效率每每沒有非公平鎖的效率高,在許多線程訪問的狀況下,公平鎖表現出較低的吞吐量。ui
ReentrantLock 總體結構以下圖:this
ReentrantLock 實現 Lock 接口,基於內部的 Sync 實現。
Sync 繼承於 AQS ,提供了 FairSync 和 NonFairSync 兩種實現。
複製代碼
Sync 是 ReentrantLock 的內部靜態類,實現 AbstractQueuedSynchronizer 抽象類,同步器抽象類。它使用 AQS 的 state 字段,來表示當前鎖的持有數量,從而實現可重入的特性。spa
/** * Performs {@link Lock#lock}. The main reason for subclassing * is to allow fast path for nonfair version. */
abstract void lock();
複製代碼
執行鎖。抽象了該方法的緣由是,容許子類實現快速得到非公平鎖的邏輯。線程
nonfairTryAcquire(int acquires) 方法,非公平鎖的方式得到鎖。代碼以下:
final boolean nonfairTryAcquire(int acquires) {
//當前線程
final Thread current = Thread.currentThread();
//獲取同步狀態
int c = getState();
//state == 0,表示沒有該鎖處於空閒狀態
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;
}
複製代碼
該方法主要邏輯:
tryRelease(int releases) 實現方法,釋放鎖。代碼以下:
protected final boolean tryRelease(int releases) {
// 減掉releases
int c = getState() - releases;
// 若是釋放的不是持有鎖的線程,拋出異常
if (Thread.currentThread() != getExclusiveOwnerThread())
throw new IllegalMonitorStateException();
boolean free = false;
// state == 0 表示已經釋放徹底了,其餘線程能夠獲取同步狀態了
if (c == 0) {
free = true;
setExclusiveOwnerThread(null);
}
setState(c);
return free;
}
複製代碼
其餘實現方法比較簡單
// 是否當前線程獨佔
@Override
protected final boolean isHeldExclusively() {
// While we must in general read state before owner,
// we don't need to do so to check if current thread is owner
return getExclusiveOwnerThread() == Thread.currentThread();
}
// 新生成條件
final ConditionObject newCondition() {
return new ConditionObject();
}
// Methods relayed from outer class
// 得到佔用同步狀態的線程
final Thread getOwner() {
return getState() == 0 ? null : getExclusiveOwnerThread();
}
// 得到當前線程持有鎖的數量
final int getHoldCount() {
return isHeldExclusively() ? getState() : 0;
}
// 是否被鎖定
final boolean isLocked() {
return getState() != 0;
}
/** * Reconstitutes the instance from a stream (that is, deserializes it). * 自定義反序列化邏輯 */
private void readObject(java.io.ObjectInputStream s) throws java.io.IOException, ClassNotFoundException {
s.defaultReadObject();
setState(0); // reset to unlocked state
}
複製代碼
從這些方法中,咱們能夠看到,ReentrantLock 是獨佔獲取同步狀態的模式。
NonfairSync 是 ReentrantLock 的內部靜態類,實現 Sync 抽象類,非公平鎖實現類。
lock() 實現方法,首先基於 AQS state 進行 CAS 操做,將 0 => 1 。若成功,則獲取鎖成功。若失敗,執行 AQS 的正常的同步狀態獲取邏輯。代碼以下:
@Override
final void lock() {
if (compareAndSetState(0, 1))
setExclusiveOwnerThread(Thread.currentThread());
else
acquire(1);
}
複製代碼
優先基於 AQS state 進行 CAS 操做,已經能體現出非公平鎖的特色。
由於,此時有可能有 N + 1 個線程正在得到鎖,其中 1個線程已經得到到鎖,釋放的瞬間,剛好被新的線程搶奪到,而不是排隊的 N 個線程。
tryAcquire(int acquires) 實現方法,非公平的方式,得到同步狀態。代碼以下:
protected final boolean tryAcquire(int acquires) {
return nonfairTryAcquire(acquires);
}
複製代碼
直接調用 #nonfairTryAcquire(int acquires) 方法,非公平鎖的方式得到鎖。
FairSync 是 ReentrantLock 的內部靜態類,實現 Sync 抽象類,公平鎖實現類。
lock() 實現方法,代碼以下:
final void lock() {
acquire(1);
}
複製代碼
直接執行 AQS 的正常的同步狀態獲取邏輯。
tryAcquire(int acquires) 實現方法,公平的方式,得到同步狀態。代碼以下:
protected final boolean tryAcquire(int acquires) {
final Thread current = Thread.currentThread();
int c = getState();
if (c == 0) {
if (!hasQueuedPredecessors() && // <1>
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;
}
複製代碼
比較非公平鎖和公平鎖獲取同步狀態的過程,會發現二者惟一的區別就在於,公平鎖在獲取同步狀態時多了一個限制條件: #hasQueuedPredecessors() 方法,是否有前序節點,即本身不是首個等待獲取同步狀態的節點。代碼以下:
// AbstractQueuedSynchronizer.java
public final boolean hasQueuedPredecessors() {
Node t = tail; //尾節點
Node h = head; //頭節點
Node s;
//頭節點 != 尾節點
//同步隊列第一個節點不爲null
//當前線程是同步隊列第一個節點
return h != t &&
((s = h.next) == null || s.thread != Thread.currentThread());
}
複製代碼
該方法主要作一件事情:主要是判斷當前線程是否位於 CLH 同步隊列中的第一個。若是是則返回 true ,不然返回 false 。
java.util.concurrent.locks.Lock 接口,定義方法以下:
void lock();
void lockInterruptibly() throws InterruptedException;
boolean tryLock();
boolean tryLock(long time, TimeUnit unit) throws InterruptedException;
void unlock();
Condition newCondition();
複製代碼
方法解釋
java.util.concurrent.locks.ReentrantLock ,實現 Lock 接口,重入鎖。
ReentrantLock 的實現方法,基本是對 Sync 的調用。
public ReentrantLock() {
sync = new NonfairSync();
}
public ReentrantLock(boolean fair) {
sync = fair ? new FairSync() : new NonfairSync();
}
複製代碼
基於 fair 參數,建立 FairSync 仍是 NonfairSync 對象。
@Override
public void lock() {
sync.lock();
}
複製代碼
@Override
public void lockInterruptibly() throws InterruptedException {
sync.acquireInterruptibly(1);
}
複製代碼
/** * Acquires the lock only if it is not held by another thread at the time * of invocation. * * <p>Acquires the lock if it is not held by another thread and * returns immediately with the value {@code true}, setting the * lock hold count to one. Even when this lock has been set to use a * fair ordering policy, a call to {@code tryLock()} <em>will</em> * immediately acquire the lock if it is available, whether or not * other threads are currently waiting for the lock. * This "barging" behavior can be useful in certain * circumstances, even though it breaks fairness. If you want to honor * the fairness setting for this lock, then use * {@link #tryLock(long, TimeUnit) tryLock(0, TimeUnit.SECONDS) } * which is almost equivalent (it also detects interruption). * * <p>If the current thread already holds this lock then the hold * count is incremented by one and the method returns {@code true}. * * <p>If the lock is held by another thread then this method will return * immediately with the value {@code false}. * * @return {@code true} if the lock was free and was acquired by the * current thread, or the lock was already held by the current * thread; and {@code false} otherwise */
@Override
public boolean tryLock() {
return sync.nonfairTryAcquire(1);
}
複製代碼
tryLock() 實現方法,在實現時,但願能快速的得到是否可以得到到鎖,所以即便在設置爲 fair = true ( 使用公平鎖 ),依然調用 Sync#nonfairTryAcquire(int acquires) 方法。
若是真的但願 #tryLock() 仍是按照是否公平鎖的方式來,能夠調用 #tryLock(0, TimeUnit) 方法來實現。
@Override
public boolean tryLock(long timeout, TimeUnit unit) throws InterruptedException {
return sync.tryAcquireNanos(1, unit.toNanos(timeout));
}
複製代碼
@Override
public void unlock() {
sync.release(1);
}
複製代碼
@Override
public Condition newCondition() {
return sync.newCondition();
}
複製代碼
public int getHoldCount() {
return sync.getHoldCount();
}
public boolean isHeldByCurrentThread() {
return sync.isHeldExclusively();
}
public boolean isLocked() {
return sync.isLocked();
}
public final boolean isFair() {
return sync instanceof FairSync;
}
protected Thread getOwner() {
return sync.getOwner();
}
public final boolean hasQueuedThreads() {
return sync.hasQueuedThreads();
}
public final boolean hasQueuedThread(Thread thread) {
return sync.isQueued(thread);
}
public final int getQueueLength() {
return sync.getQueueLength();
}
protected Collection<Thread> getQueuedThreads() {
return sync.getQueuedThreads();
}
public boolean hasWaiters(Condition condition) {
if (condition == null)
throw new NullPointerException();
if (!(condition instanceof AbstractQueuedSynchronizer.ConditionObject))
throw new IllegalArgumentException("not owner");
return sync.hasWaiters((AbstractQueuedSynchronizer.ConditionObject)condition);
}
public int getWaitQueueLength(Condition condition) {
if (condition == null)
throw new NullPointerException();
if (!(condition instanceof AbstractQueuedSynchronizer.ConditionObject))
throw new IllegalArgumentException("not owner");
return sync.getWaitQueueLength((AbstractQueuedSynchronizer.ConditionObject)condition);
}
protected Collection<Thread> getWaitingThreads(Condition condition) {
if (condition == null)
throw new NullPointerException();
if (!(condition instanceof AbstractQueuedSynchronizer.ConditionObject))
throw new IllegalArgumentException("not owner");
return sync.getWaitingThreads((AbstractQueuedSynchronizer.ConditionObject)condition);
}
複製代碼
前面提到 ReentrantLock 提供了比 synchronized 更加靈活和強大的鎖機制,那麼它的靈活和強大之處在哪裏呢?他們之間又有什麼相異之處呢?
首先他們確定具備相同的功能和內存語義。