本質(zhì)
java鎖的實(shí)現(xiàn)原理就是繼承AQS抽象類
java鎖繼承Lock接口,
而Lock需要實(shí)現(xiàn)的接口依賴AQS的實(shí)現(xiàn)。
AQS用來實(shí)現(xiàn)具體鎖的操作,需要具體鎖去重寫tryAcquire(獲取鎖時(shí)根據(jù)具體場景使用CAS算法嘗試修改state狀態(tài)),tryRelease(釋放鎖根據(jù)具體場景使用CAS算法嘗試修改state狀態(tài))和isHeldExclusively(用來判斷當(dāng)前鎖是被線程獨(dú)占還是共享)等AQS可支持重寫的函數(shù)
注意tryAcquire和acquire區(qū)別。前者需要用戶去根據(jù)鎖類型自己實(shí)現(xiàn)的子類嘗試修改state狀態(tài)。后者是AQS抽象類實(shí)現(xiàn)獲取鎖操作的流程實(shí)現(xiàn)。
模板方法設(shè)計(jì)模式。
子類還需定義其acquire和release時(shí)的state的增減代表什么含義。
獲取鎖釋放鎖流程
獨(dú)占鎖
線程綁定,獲取到了資源后其他線程嘗試操作state會獲取失敗后阻塞。
- 例如:重入鎖
當(dāng)一個(gè)線程獲取重入鎖后,AQS內(nèi)部會把state用CAS將其從0改成1,且設(shè)置當(dāng)前線程位鎖的持有者。
當(dāng)該線程再次獲取這把鎖時(shí),state從1改為2,即可重入次數(shù)。
而當(dāng)另一個(gè)線程獲取時(shí)就會被放入ASQ阻塞隊(duì)列。(注意和condition里await后的條件隊(duì)列做區(qū)別。)
acquire實(shí)現(xiàn)(待續(xù))
release實(shí)現(xiàn)(待續(xù))
共享鎖
和具體線程不相關(guān)。
多個(gè)線程去請求資源時(shí)通過CAS方式競爭獲取資源,而一個(gè)線程獲取資源后,另一個(gè)線程在此獲取時(shí)如果當(dāng)前資源能滿足它的需要就直接CAS獲取。
- 例如:Semaphore(信號量)
一個(gè)線程通過acquire方法獲取信號量時(shí),看當(dāng)前信號量是否滿足需要,
是就通過CAS獲取信號量。
否就放入阻塞隊(duì)列
- 例如:讀寫鎖
檢查是否被其他線程占有,如果空閑使用CAS遞增高16位(獲取讀鎖的次數(shù))
acquire實(shí)現(xiàn)(待續(xù))
release實(shí)現(xiàn)(待續(xù))
類圖
關(guān)鍵組件和字段
AQS(FIFO雙向隊(duì)列)
head指針
tail指針
waitStatus記錄當(dāng)前線程等待狀態(tài)
prev指針
next指針
state
維持了單一的狀態(tài),可以通過comareAbdSetState修改其值
線程同步的關(guān)鍵是對state進(jìn)行操作(acquire,release等)
重入鎖的state:標(biāo)識當(dāng)前線程獲取鎖的可重入次數(shù)
讀寫鎖的state:其高16位是獲取讀鎖的次數(shù),低16位是寫鎖的可重入次數(shù)
CountDownlatch:計(jì)數(shù)器當(dāng)前值
等 ...
Node
進(jìn)入阻塞時(shí)(進(jìn)入AQS隊(duì)列)的線程的包裝類。
其內(nèi)部維護(hù)了幾個(gè)標(biāo)記:
1.是否時(shí)獲取共享資源而進(jìn)入AQS隊(duì)列
2.是否是獲取獨(dú)占資源...
Condition(條件變量)
每個(gè)Condition對應(yīng)一個(gè)條件隊(duì)列(單向鏈表),用來存await后被阻塞的線程。
notify和wait是synchronized內(nèi)置鎖實(shí)現(xiàn)線程同步的原語。
而Condition的signal和await方法就是配合基于AQS實(shí)現(xiàn)的鎖實(shí)現(xiàn)線程同步的原語。
兩者不同點(diǎn)在于,synchronized只同時(shí)支持一個(gè)共享變量的notify和wait。
AQS可以支持多個(gè)condition。。
同樣的,也有signalAll方法。
導(dǎo)圖鏈接:
http://naotu.baidu.com/file/d60acad54746a9b7b3c918bf6be36b7f?token=ce79d14db33d3d35