ReentrantLock是java1.5中lock框架中Lock接口的一個實現類.一個ReentrantLock的實例鎖擁有和synchronized相同的行為和語義,并且還擴展了其他能力.
ReentrantLock是通過一種什么機制來實現鎖的呢?也就是說ReentrantLock到底是鎖住了什么東西來控制線程同步的呢?下面將詳細講解.
ReentrantLock內部實現了一個AbstractQueuedSynchronizer的同步器,ReentrantLock就是通過控制這個AbstractQueuedSynchronizer同步器來實現多個線程之間的同步.那么具體的實現原理是怎么樣的呢?
AbstractQueuedSynchronizer類會維護一個等待隊列,并且擁有一個state(volatile修飾)的成員變量屬性,AbstractQueuedSynchronizer就是通過這個state來控制多個線程的同步訪問的.當ReentrantLock調用lock()方法時,內部實際調用的是Sync(AbstractQueuedSynchronizer的實現類)的lock方法,此方法會先判斷AbstractQueuedSynchronizer中state屬性的值:如果state!=0,說明當前有線程在占用鎖資源,然后接著判斷當前占用該鎖資源的線程是否跟當前線程是同一個線程,如果是同一個線程那么state值就加一,同時當前線程繼續執行,如果不是同一個線程,那么就會把當前線程加入等待隊列(并且會一直嘗試獲取鎖資源).如果state==0,說明當前鎖資源是可用,那么直接設置當前線程占用了鎖資源并返回繼續執行.執行完成之后,必須要手動釋放鎖資源.
下面對ReentrantLock的源碼并相關類源碼進行解讀:
類定義
public class ReentrantLock implements Lock, java.io.Serializable
成員變量
修飾符 | 變量名 | 作用 |
---|---|---|
private final Sync | sync | 實際同步鎖控制實例 |
構造方法
無參構造方法
無參構造方法會給sync賦值,默認賦值為不公平鎖同步(公平鎖,不公平鎖下面會講)
public ReentrantLock() {
sync = new NonfairSync();
}
有參構造方法
參數:
true 公平鎖,線程獲取鎖的順序跟等待的時間有關,先等待的線程先獲取鎖
false 不公平鎖,線程獲取鎖是隨機的
public ReentrantLock(boolean fair) {
sync = fair ? new FairSync() : new NonfairSync();
}
核心方法講解
lock()方法
public void lock() {
// 調用Sync(Sync是AbstractQueuedSynchronizer的子類)的lock()方法
// Sync是ReentrantLock的內部類,同時在ReentrantLock中有兩種實現方式
// 1. FairSync(公平實現)
// 2. NonFairSync(不公平實現)
sync.lock();
}
-- ------------------------------------------------------ --
-- ---------------FairSync獲取鎖的實現-------------------- --
-- ------------------------------------------------------ --
/**
* FairSync的lock方法實現
**/
final void lock() {
// acquire方法是AbstractQueuedSynchronizer中的方法
// 此方法會調用tryAcquire(int)方法來試圖獲取鎖資源
acquire(1);
}
/**
* AbstractQueuedSynchronizer中acquire()方法的實現
**/
public final void acquire(int arg) {
// 試圖獲取鎖資源(會調用對應實現的tryAcquire()方法),
// 不成功則加入等待隊列并獲取隊列(addWaiter()會將當前線程加入到等待隊列尾部)
// acquireQueued()(不知道怎么說,等會直接講代碼)
if (!tryAcquire(arg) &&
acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
selfInterrupt();
}
/**
* FairSync中tryAcquire()的實現
* 返回
* true: 獲取鎖成功
* false: 獲取鎖不成功
**/
protected final boolean tryAcquire(int acquires) {
// 獲取當前線程
final Thread current = Thread.currentThread();
// 獲取鎖資源的狀態
// 0: 說明當前鎖可立即獲取,在此種狀態下(又是公平鎖)
// >0并且當前線程與持有鎖資源的線程是同一個線程則state + 1并返回true
// >0并且占有鎖資源的不是當前線程,則返回false表示獲取不成功
int c = getState();
if (c == 0) {
// 在鎖可以立即獲取的情況下
// 首先判斷線程是否是剛剛釋放鎖資源的頭節點的下一個節點(線程的等待先后順序)
// 如果是等待時間最長的才會馬上獲取到鎖資源,否則不會(這也是公平與不公平的主要區別所在)
if (!hasQueuedPredecessors() &&
compareAndSetState(0, acquires)) {
setExclusiveOwnerThread(current);
return true;
}
}
else if (current == getExclusiveOwnerThread()) { //線程可以遞歸獲取鎖
int nextc = c + acquires;
// 超過int上限值拋出錯誤
if (nextc < 0)
throw new Error("Maximum lock count exceeded");
setState(nextc);
return true;
}
return false;
}
/**
* AbstractQueuedSynchronizer中acquireQueued()方法講解
**/
final boolean acquireQueued(final Node node, int arg) {
boolean failed = true;
try {
boolean interrupted = false;
// 注意這里的無限循環(表現出來就是等待的一個過程)
for (;;) {
// 獲得前一個非null節點
final Node p = node.predecessor();
// 如果前任節點是頭結點(頭節點是表示獲取到了資源鎖的節點)
// 并且試圖獲取鎖資源(只有在p節點release()掉鎖資源才會獲取成功)
// 如果獲取鎖資源成功,就將此線程節點設置為頭結點,并把p節點的引用斷開
// 獲取鎖成功就退出循環
if (p == head && tryAcquire(arg)) {
setHead(node);
p.next = null; // help GC
failed = false;
return interrupted;
}
// 如果獲取資源失敗了,那就先判斷線程是否需要被阻塞,需要就阻塞線程
if (shouldParkAfterFailedAcquire(p, node) &&
parkAndCheckInterrupt())
interrupted = true;
// 繼續循環等待
}
} finally {
// 如果獲取鎖資源失敗了,
// 那么就把線程的等待狀態設置為cancelled(此狀態的線程不會再獲得鎖資源)
if (failed)
cancelAcquire(node);
}
}
-- ------------------------------------------------------ --
-- ---------------NonFairSync獲取鎖的實現----------------- --
-- ------------------------------------------------------ --
/**
* lock()方法實現
**/
final void lock() {
// 如果鎖空閑則立即獲取鎖資源,設置鎖資源的當前占用線程
if (compareAndSetState(0, 1))
setExclusiveOwnerThread(Thread.currentThread());
else
// acquire()過程跟FairSync是一樣的,
// 主要區別在于NonFairSync的tryAcqure()有不同的實現
acquire(1);
}
/**
* tryAcquire()方法實現
* 調用的nonfairTryAcquire()方法,這是父類Sync中的方法實現
**/
protected final boolean tryAcquire(int acquires) {
return nonfairTryAcquire(acquires);
}
/**
* Sync中的nonfairTryAcquire()方法實現
* 這個跟公平類中的實現主要區別在于不會判斷當前線程是否是等待時間最長的線程
**/
final boolean nonfairTryAcquire(int acquires) {
final Thread current = Thread.currentThread();
int c = getState();
if (c == 0) {
// 跟FairSync中的主要區別,不會判斷hasQueuedPredecessors()
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;
}
unlock()方法
釋放線程占用的鎖
public void unlock() {
// 調用Sync中的release()方法,所以公平和不公平類釋放鎖是一樣的
// 實際調用AbstractQueuedSynchronizer中的release()
sync.release(1);
}
/**
* AbstractQueuedSynchronizer中的release()
**/
public final boolean release(int arg) {
// 釋放鎖資源,子類會重寫這個方法(在這里就是調用的Sync中tryRelease())
if (tryRelease(arg)) {
// 釋放鎖資源成功后,會執行一個喚醒后續線程(喚醒一個)的操作
Node h = head;
if (h != null && h.waitStatus != 0)
unparkSuccessor(h);
return true;
}
return false;
}
/**
* Sync中tryRelease()
**/
protected final boolean tryRelease(int releases) {
// 修改當前鎖的狀態
// 如果一個線程遞歸獲取了該鎖(也就是state != 1), 那么c可能不等0
// 如果沒有線程遞歸獲取該鎖,則c == 0
int c = getState() - releases;
// 如果鎖的占有線程不等于當前正在執行釋放操作的線程,則拋出異常
if (Thread.currentThread() != getExclusiveOwnerThread())
throw new IllegalMonitorStateException();
boolean free = false;
// c == 0,表示當前線程釋放鎖成功,同時表示遞歸獲取了該鎖的線程已經執行完畢
// 則設置當前鎖狀態為free,同時設置鎖的當前線程為null,可以讓其他線程來獲取
// 同時也說明,如果c != 0,則表示線程遞歸占用了鎖資源,
// 所以鎖的當前占用線程依然是當前釋放鎖的線程(實際沒有釋放)
if (c == 0) {
free = true;
setExclusiveOwnerThread(null);
}
// 重新設置鎖的占有數
setState(c);
return free;
}
條件鎖的操作
public Condition newCondition() {
return sync.newCondition();
}
這里不對源碼進行解讀,只對原理進行一個說明,上述函數實際上是執行了一個new ConditionObject();的操作,
這個類是同步器中的一個內部類,這個類內部是維護了一個條件隊列,條件鎖的操作也是針對這個條件隊列的一個操作.