### 鎖---預備知識Java的AQS
鎖—預備知識Java的AQS
****************** 如有侵權請提示刪除 *******************
1、概念:
所謂AQS,指的是AbstractQueuedSynchronizer,它提供了一種實現阻塞鎖和一系列依賴FIFO等待佇列的同步器的框架,ReentrantLock、Semaphore、CountDownLatch、CyclicBarrier等併發類均是基於AQS來實現的,具體用法是通過繼承AQS實現其模板方法,然後將子類作為同步元件的內部類。
瞭解一個框架最好的方式是讀原始碼,說幹就幹。
AQS是JDK1.5之後才出現的,由大名鼎鼎的Doug Lea李大爺來操刀設計並開發實現,全部原始碼(加註釋)2315行,整體難度中等。
基本框架
AQS維護了一個volatile語義(支援多執行緒下的可見性)的共享資源變數state和一個FIFO執行緒等待佇列(多執行緒競爭state被阻塞時會進入此佇列)。
state的訪問方式有三種:
getState()
setState()
compareAndSetState()
AQS定義兩種資源共享方式:Exclusive(獨佔,只有一個執行緒能執行,如ReentrantLock)和Share(共享,多個執行緒可同時執行,如Semaphore/CountDownLatch)。
不同的自定義同步器爭用共享資源的方式也不同。自定義同步器在實現時只需要實現共享資源state的獲取與釋放方式即可,至於具體執行緒等待佇列的維護(如獲取資源失敗入隊/喚醒出隊等),AQS已經在頂層實現好了。自定義同步器實現時主要實現以下幾種方法:
1 isHeldExclusively():該執行緒是否正在獨佔資源。只有用到condition才需要去實現它。 2 tryAquire(int):獨佔方式。嘗試獲取資源,成功則返回true,失敗則返回false。 3 tryRelease(int):獨佔方式。嘗試釋放資源,成功則返回true,失敗則返回false。 4 tryAcquireShared(int):共享方式。嘗試獲取資源。負數表示失敗;0表示成功,但沒有剩餘可用資源;正數表示成功,且有剩餘資源。 5 tryReleaseShared(int):共享方式。嘗試釋放資源,如果釋放後允許喚醒後續等待結點返回true,否則返回false。
以ReentrantLock為例,state初始化為0,表示未鎖定狀態。A執行緒lock()時,會呼叫tryAcquire()獨佔該鎖並將state+1。此後,其他執行緒再tryAcquire()時就會失敗,直到A執行緒unlock()到state=0(即釋放鎖)為止,其他執行緒才有機會獲取該鎖。當然,釋放鎖之前,A執行緒自己是可以重複獲取此鎖的(state會累加),這就是可重入的概念。但要注意,獲取多少次就要釋放多少次,這樣才能保證state是能回到零態的。
再以CountDownLatch為例,任務分為N個子執行緒去執行,state為初始化為N(注意N要與執行緒個數一致)。這N個子執行緒是並行執行的,每個子執行緒執行完後countDown()一次,state會CAS減1。等到所有子執行緒都執行完後(即state=0),會unpark()主呼叫執行緒,然後主呼叫執行緒就會await()函式返回,繼續後餘動作。
一般來說,自定義同步器要麼是獨佔方法,要麼是共享方式,他們也只需實現tryAcquire-tryRelease、tryAcquireShared-tryReleaseShared中的一種即可。但AQS也支援自定義同步器同時實現獨佔和共享兩種方式,如ReentrantReadWriteLock。