初識Lock體系

1.Lock體系

 


目錄

1.Lock體系

1.1Lock簡介

1.1.2 Lock 接口API

1.1.3初始AQS

1.1.4AQS的模板方法設計模式

AQS可重寫的方法如下圖(protected方法)

在實現同步組件時AQS提供的模板方法如下圖:(底層實際操作)


1.1Lock簡介

Lock:鎖是用來控制多個線程訪問共享資源的方式,一般來說能夠防止多個線程訪問共享資源。在Lock接口出現之前是靠synchronized關鍵字來實現鎖的功能的,而JDK5之後,併發包中增加了lock接口,它提供了與

synchronized一樣的鎖功能。

lock和sychronized特點:

相比sychronized而言雖然失去了synchronized關鍵字隱式的加鎖解鎖得便捷性,但是卻擁有了鎖獲取和釋放得可操作性,可中斷的獲取鎖以及超時獲取鎖等多種synchronized關鍵字鎖具備的同步特性。通常使用顯示使用lock的形式如下:

lock的標準使用形式

Lock lock = new ReentrantLock();

lock.lock(); 

try{    ....... 

}finally{    

lock.unlock();

}

需要注意的是:lock必須使用ubLock()方法釋放鎖,因爲此在final塊中釋放了鎖

 

1.1.2 Lock 接口API

 

 

LocK 接口實現的子類

ReadWiteLock

ReentrantLock

ReentrantReadWitrLock

StampedLock

 

基本上所有方法的實現都是調用了其靜態內存類Sync中的方法,而Sync類繼承了AbstractQueuedSynchronizer(AQS)

則ReentrantLock關鍵的核心在於隊列同步器AbstractQueuedSynchronizer(AQS)。(同步器的理解)

 

1.1.3初始AQS

同步器是用來構建和其他同步組件的基本框架,它的實現主要依賴一個int成員的變量來表示當前狀態以及通過一個FIFO隊列後成的等待隊列。他的子類必須覆寫AQS的幾個protected修飾的用來改變同步狀態的方法,其他方法主要是實現了排隊和阻塞機制。狀態更新使用getState,setState,以及compareAndSetState這三個方法

子類被推薦定義爲自定義同步組件的靜態內部類(Sync),同步器自身沒有實現任何同步接口,它僅僅是定義了若干同步狀 態的獲取和釋放方法來供自定義同步組件的使用,同步器既支持獨佔式獲取同步狀態,也可以支持共享式獲取同步 狀態,這樣就可以方便的實現不同類型的同步組件。

同步器是實現鎖(也可以是任意同步組件)的關鍵,在鎖的實現中聚合同步器,利用同步器實現鎖的語義。可以這 樣理解二者的關係:(lock)鎖是面向使用者,它定義了使用者與鎖交互的接口,隱藏了實現細節;(AQS)同步器是面向鎖的實現 者,它簡化了鎖的實現方式,屏蔽了同步狀態的管理,線程的排隊,等待和喚醒等底層操作。鎖和同步器很好的隔 離了使用者和實現者所需關注的領域。

 

1.1.4AQS的模板方法設計模式

AQS的設計是使用模板方法設計模式,它將一些方法開放給子類進行重寫,而同步器給同步器組件所提供模板方法又會重新調用被子類所覆寫的方法。舉個列子,AQS中需要重寫的方法tryAcquire:

protected boolean tryAcquire(int arg) {

throw new UnsupportedOperationException();

}

ReentrantLock中NonfairSync(繼承AQS)



protected final boolean tryAcquire(int acquires) {

    return nonfairTryAcquire(acquires);

}

AQS中的模板方法acqire();會調用tryAcquire方法,而此時當繼承AQS的NonfairSync(不公平鎖)調用模板方法acquire時就會調用已經被NonfairSync重寫的 tryAcquire方法。這就是使用AQS的方式。

 

在弄懂這點後會lock的實現理解有很大的提升。可以歸納總結爲這麼幾 點:

public final void acquire(int arg) {

    if (!tryAcquire(arg) &&

        acquireQueued(addWaiter(Node.EXCLUSIVE), arg))

        selfInterrupt();

}

 


1.同步組件(這裏不僅僅指鎖,還包括CountDownLatch等)的實現依賴於同步器AQS。

在同步組件實現中,使用 AQS的方式被推薦定義繼承AQS的靜態內存類

 

例如:ReentrantLock中 Sync類繼承AQS

但ReentrantLock中有FairSync共公鎖,NonfairSync非公平鎖。所以又繼承Sync類,來覆寫AQS中的protected方法tryLock,tryRealse()

 

在當其調用AQS 的acquire()方法時就會調用 兩個FairSync NonfairSync 所覆寫的方法。達到自定義的目的。

實現其排隊阻塞機制(即實現了同步的語義),並沒有具體去實現AQS中的實際底層操作方法。

1. AQS採用模板方法進行設計,AQS的protected修飾的方法需要由繼承AQS的子類進行重寫實現,當調用AQS的子 類的方法時就會調用被重寫的方法;

2. AQS負責同步狀態的管理,線程的排隊,等待和喚醒這些底層操作,而Lock等同步組件主要專注於實現同步語義;

3.在重寫AQS的方式時,使用AQS提供的getState(),setState(),compareAndSetState()方法進行修改同步狀態

 


 

  • AQS可重寫的方法如下圖(protected方法)

 


  • 在實現同步組件時AQS提供的模板方法如下圖:(底層實際操作

 

 

AQS提供的模板方法可分爲3類

1.獨佔式獲取與釋放同步狀態;

2.共享式獲取與釋放同步狀態;

3.查詢同步隊列中等待線程情況;

 

同步組件通過過AQS提供的模板方法去實現自己的同步語義。

 

   1.實現同步組件時推薦定義繼承AQS的靜態內存類,並重寫需要的protected修飾的方法;

   2.同步組件語句的實現依賴於AQS的模板方法,而AQS模板方法又依賴於AQS子類所覆寫的方法

 

總的來說,同步組件通過重寫AQS的方法來實現自己想要表達的同步語義,而AQS只需要同步組件表達式的true和false即可,AQS會針對true和false不同情況下做不同的處理。

因爲AQS中acquire方法用tryAcquire方法作爲if判斷的語句塊中的第一個判斷條件,假如判斷爲真則CAS操作成功,直接退出。線程獲取到鎖。

AQS-acquire

public final void acquire(int arg) {

if (!tryAcquire(arg) &&

acquireQueued(addWaiter(Node.EXCLUSIVE), arg))

selfInterrupt();

}

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章