什麼是ReentrantLock
-
ReentrantLock是一個可重入的互斥鎖鎖, 實現Lock介面。具有與使用 synchronized 方法和語句所訪問的隱式監視器鎖相同的一些基本行為和語義。ReentrantLock是顯示的獲取或釋放鎖,並且有鎖超時,鎖中斷等功能。
-
內部維戶了一個Sync的內部類,繼承AQS佇列同步器。
-
ReentrantLock 將由最近成功獲得鎖,並且還沒有釋放該鎖的執行緒所擁有。當鎖沒有被另一個執行緒所擁有時,呼叫 lock 的執行緒將成功獲取該鎖並返回。如果當前執行緒已經擁有該鎖,此方法將立即返回。可以使用 isHeldByCurrentThread() 和 getHoldCount() 方法來檢查此情況是否發生。
-
預設是非公平鎖的實現方式
非公平鎖獲取和釋放流程
加鎖
- 執行
lock
方法加鎖時呼叫內部NonfairSync
的lock
方法,第一次會快速嘗試獲取鎖,執行AQS
類的compareAndSetState
方法(CAS)更改同步狀態成員變數state
,如果獲取成功 則設定當前執行緒為鎖的持有者。失敗則執行AQS
類的acquire
方法,acquire
會呼叫的AQS
中的tryAcquire
方法。這個tryAcquire
方法需要自定義同步元件提供實現。 tryAcquire
的具體流程是執行Sync
類的nonfairTryAcquire
方法:首先記錄當前加鎖執行緒,然後呼叫getState
獲取同步狀態,如果為0時 說明鎖處於空閒狀態,可以獲取,會以CAS
方式修改state
變數。成功則設定當前執行緒 返回true
。否則執行重入判斷,判斷當前訪問執行緒和已經持有鎖的執行緒是否是同一個。如果相同,將同步狀態值進行增加,並返回true。否則返回加鎖失敗false
解鎖
- 解鎖
unlock
方法會呼叫內部類Sync
的tryRelease
方法。tryRelease
首先呼叫getState
方法獲取同步狀態,並進行了減法操作。在判斷釋放操作是不是當前執行緒,不是則丟擲異常,然後判斷同步狀態是否等於0,如果是0,說明沒有執行緒持有,鎖是空閒的,則將當前鎖的持有者設定為null
, 方便其它執行緒獲取,並返回true
。否則返回false
ReentrantLock常用方法介紹
getHoldCount()
查詢當前執行緒保持此鎖的次數。getOwner()
返回目前擁有此鎖的執行緒getQueueLength()
返回正等待獲取此鎖的執行緒估計數getWaitingThreads(Condition condition)
返回一個 collection,它包含可能正在等待與此鎖相關給定條件的那些執行緒。boolean hasQueuedThread(Thread thread)
查詢給定執行緒是否正在等待獲取此鎖。boolean hasQueuedThreads()
查詢是否有些執行緒正在等待獲取此鎖。boolean hasWaiters(Condition condition)
查詢是否有些執行緒正在等待與此鎖有關的給定條件boolean isHeldByCurrentThread()
查詢當前執行緒是否保持此鎖。void lock()
獲取鎖。void lockInterruptibly()
如果當前執行緒未被中斷,則獲取鎖。Condition newCondition()
返回用來與此 Lock 例項一起使用的 Condition 例項。boolean tryLock()
僅在呼叫時鎖未被另一個執行緒保持的情況下,才獲取該鎖。void unlock()
釋放鎖
程式中使用
private ReentrantLock lock=new ReentrantLock();
private int i=0;
public void a(){
lock.lock();
i++;
lock.unlock();
}
複製程式碼
ReentrantLock原始碼分析
package java.util.concurrent.locks;
import java.util.concurrent.TimeUnit;
import java.util.Collection;
public class ReentrantLock implements Lock, java.io.Serializable {
private static final long serialVersionUID = 7373984872572414699L;
private final Sync sync;
/**內部維護的一個幫助類,繼承成AQS 鎖的獲取和釋放主要靠它**/
abstract static class Sync extends AbstractQueuedSynchronizer {
private static final long serialVersionUID = -5179523762034025860L;
abstract void lock();
/**
* 執行非公平的t加鎖
*/
final boolean nonfairTryAcquire(int acquires) {
//記錄當前加鎖執行緒
final Thread current = Thread.currentThread();
//獲取同步狀態 AQS中的volatile修飾的int型別成員變數 state
int c = getState();
//為0時 說明鎖處於空閒狀態,可以獲取
if (c == 0) {
// CAS方式修改state。成功則設定當前執行緒 返回true
if (compareAndSetState(0, acquires)) {
setExclusiveOwnerThread(current);
return true;
}
}
//執行緒重入判斷,判斷當前訪問執行緒和已經持有鎖的執行緒是否是同一個
else if (current == getExclusiveOwnerThread()) {
//將同步狀態值進行增加
if (nextc < 0) // overflow
throw new Error("Maximum lock count exceeded");
//設定同步狀態,重入鎖的話就累加,並返回true
setState(nextc);
return true;
}
return false;
}
//釋放鎖,就是把AQS中的同步狀態變數就行類減直到0 就是出於空閒狀態了
protected final boolean tryRelease(int releases) {
int c = getState() - releases;
//如果釋放操作不是當前執行緒 則丟擲異常
if (Thread.currentThread() != getExclusiveOwnerThread())
throw new IllegalMonitorStateException();
boolean free = false;
//同步狀態等於0,說明沒有執行緒持有,鎖是空閒的
if (c == 0) {
free = true;
//當前鎖的持有者 設定為null 方便其它執行緒獲取
setExclusiveOwnerThread(null);
}
//如果該鎖被獲取了n次,那麼前(n-1)次tryRelease(int releases)方法必須返回false
setState(c);
return free;
}
protected final boolean isHeldExclusively() {
return getExclusiveOwnerThread() == Thread.currentThread();
}
final ConditionObject newCondition() {
return new ConditionObject();
}
//返回目前擁有此鎖的執行緒,如果此鎖不被任何執行緒擁有,則返回 null。
final Thread getOwner() {
return getState() == 0 ? null : getExclusiveOwnerThread();
}
//查詢當前執行緒保持此鎖的次數。
final int getHoldCount() {
return isHeldExclusively() ? getState() : 0;
//查詢鎖是否被持有
final boolean isLocked() {
return getState() != 0;
}
private void readObject(java.io.ObjectInputStream s)
throws java.io.IOException, ClassNotFoundException {
s.defaultReadObject();
setState(0); // reset to unlocked state
}
}
//非公平的 Sync的子類
static final class NonfairSync extends Sync {
private static final long serialVersionUID = 7316153563782823691L;
final void lock() {
//第一次快速獲取鎖,使用CAS 方式 成功設定當前執行緒為鎖的持有者
if (compareAndSetState(0, 1))
setExclusiveOwnerThread(Thread.currentThread());
else
//鎖獲取失敗時,呼叫AQS的acquire去獲取鎖,
//acquire會呼叫tryAcquire方法,tryAcquire需要自定義同步元件提供實現,
//所以這裡的呼叫邏輯是acquire-》tryAcquire(NonfairSync類的)-》Sync的nonfairTryAcquire方法
acquire(1);
}
//呼叫父類nonfairTryAcquire 實現加鎖
protected final boolean tryAcquire(int acquires) {
return nonfairTryAcquire(acquires);
}
}
//公平的 Sync的子類
static final class FairSync extends Sync {
private static final long serialVersionUID = -3000897897090466540L;
// 加鎖 呼叫AQS中的acquire方法,acquire會呼叫下面的tryAcquire方法
final void lock() {
acquire(1);
}
//加鎖的過程,和父類的呼叫父類nonfairTryAcquire方法大致一樣
//唯一不同的位置為判斷條件多了hasQueuedPredecessors()方法
protected final boolean tryAcquire(int acquires) {
final Thread current = Thread.currentThread();
int c = getState();
if (c == 0) {
//公平鎖實現的關鍵點hasQueuedPredecessors
/**
即加入了同步佇列中當前節點是否有前驅節點的判斷
如果該方法返回true,則表示有執行緒比當前執行緒更早地請求獲取鎖
因此需要等待前驅執行緒獲取並釋放鎖之後才能繼續獲取鎖
*/
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;
}
}
//AQS中的方法 判斷當前執行緒是否位於CLH同步佇列中的第一個。如果是則返回true,否則返回false。
public final boolean hasQueuedPredecessors() {
Node t = tail; // Read fields in reverse initialization order
Node h = head;
Node s;
return h != t &&((s = h.next) == null || s.thread != Thread.currentThread());
}
//預設的建構函式 非公平鎖
public ReentrantLock() { sync = new NonfairSync();}
//為true 公平鎖
public ReentrantLock(boolean fair) {
sync = fair ? new FairSync() : new NonfairSync();
}
public void lock() { sync.lock();}
public void lockInterruptibly() throws InterruptedException {
sync.acquireInterruptibly(1);
}
public boolean tryLock() { return sync.nonfairTryAcquire(1);}
public boolean tryLock(long timeout, TimeUnit unit) throws InterruptedException {
return sync.tryAcquireNanos(1, unit.toNanos(timeout));
}
//釋放鎖
public void unlock() { sync.release(1);}
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);
}
}
複製程式碼
- 參考併發程式設計的藝術
- jdk8原始碼
- 我的部落格:blog.qinxuewu.club/
- Github: github.com/a870439570