本文用於記錄在學習AQS時,以ReentrantLock為切入點,深入原始碼分析ReentrantLock的加鎖和解鎖過程。
同步器AQS的主要使用方式是繼承,子類通過繼承同步器並實現它的抽象方法來管理同步狀態(通常鎖或者同步元件內部會實現一個Sync類(該類是一個靜態內部類),然後讓Sync類去繼承AQS類,通過繼承AQS佇列同步器並實現它的抽象方法來管理同步狀態),對同步狀態進行更改需要使用同步器提供的3個方法 getState
、setState
和 compareAndSetState
,它們保證狀態改變是安全的。
下圖是ReentrantLock中所有的內部類和方法:
3個內部類之間的關係如下圖所示:
以ReentrantLock為例,從原始碼分析如何進行加鎖和解鎖。
ReentrantLock lc = new ReentrantLock();
lc.lock();
lc.unlock();
(1)ReentrantLock建構函式(為了方便分析,我們以非公平佇列為例子)
(2)lc.lock()
ReentrantLock類中的lock()
方法呼叫sync例項中的lock()方法,因為我們是以非公平佇列為例子,所以此時的sync例項的型別為NonfairSync。即呼叫NonfairSync.lock()
緊接著進入209行對應的acquire(1)方法:該方法位於AQS框架中,且被final修飾,即不能被子類重寫。
緊接著進入tryAcquire(int arg)方法
我們發現AQS中的tryAcquire(int arg)方法中沒有實現體,說明tryAcquire(int arg)方法需要AQS子類實現,根據上面的繼承圖可知,Sync以及NonfairSync都是AQS的子類,由下圖可知,tryAcquire(int arg)方法的實現位於NonfairSync內部類中
進入NonfairSync內部類中的ryAcquire(int arg)方法可以發現其呼叫了Sync靜態內部類中的nonfairTryAcquire方法。
至此成功獲取了鎖。
(1) 通過ReentrantLock的加鎖方法Lock進行加鎖操作。
(2) 會呼叫到內部類Sync的Lock方法,根據ReentrantLock初始化選擇的公平鎖和非公平鎖,執行相關內部類的Lock方法,本質上都會執行AQS的acquire方法。
(3) AQS的Acquire方法會執行tryAcquire方法,但是由於tryAcquire需要自定義同步器實現,因此執行了ReentrantLock中的tryAcquire方法,由於ReentrantLock是通過公平鎖和非公平鎖內部類實現的tryAcquire方法,因此會根據鎖型別不同,執行不同的tryAcquire。
(4) tryAcquire是獲取鎖邏輯,獲取失敗後,會執行框架AQS的後續邏輯,跟ReentrantLock自定義同步器無關。
(3)lc.unlock()
釋放鎖的過程和加鎖過程類似,不走進原始碼,直接上文字版流程
(1) 通過ReentrantLock的解鎖方法Unlock進行解鎖。
(2) Unlock會呼叫內部類Sync的release方法,該方法繼承於AQS。
(3) release中會呼叫tryRelease方法,tryRelease需要自定義同步器實現,tryRelease只在ReentrantLock中的Sync實現,因此可以看出,釋放鎖的過程,並不區分是否為公平鎖。
(4) 釋放成功後,所有處理由AQS框架完成,與自定義同步器無關。
經過上述的學習,可以歸納總結出如果要自定義一個同步元件,可以按照如下步驟
- 第一步:內部寫一個Sync類繼承
AbstractQueuedSynchronizer
介面。 - 第二步:根據是否獨佔來重寫佇列同步器中的方法,如果需要獨佔則實現
tryAcquire()/tryRelease()
等方法,如果不需要獨佔,則實現tryAcquireShared(int acquires)和tryReleaseShared(int releases)
等方法。 - 第三步:初始化Sync物件,並在鎖的獲取/釋放方法(通常為lock()以及unlock()方法)中呼叫AQS的
acquire()/release()
或者acquireShared()/releaseShared()
方法。