reentrantlock主要由li大師編寫的可重入鎖,可以說當時是為了替代synchronized而誕生的,因為synchronized當時是乙個重量級鎖,消耗效能,可能造成效能的急劇降低,隨著後來synchronized的不斷的優化,效能逐漸超過reentrantlock,而reentrantlock,reentrantreadwritelock等鎖底層都是基於aqs來實現的。
synchronized是可以作用與方法,類和**塊,是乙個自動加鎖和釋放鎖的。
?reentrantlock加鎖和釋放鎖的底層原理
好了,那麼現在如果有乙個執行緒過來嘗試用reentrantlock的lock()方法進行加鎖,會發生什麼事情呢?
很簡單,這個aqs物件內部有乙個核心的變數叫做state,是int型別的,代表了加鎖的狀態。初始狀態下,這個state的值是0。 另外,這個aqs內部還有乙個關鍵變數,用來記錄當前加鎖的是哪個執行緒,初始化狀態下,這個變數是null。
接著執行緒1跑過來呼叫reentrantlock的lock()方法嘗試進行加鎖,這個加鎖的過程,直接就是用cas操作將state值從0變為1。
如果之前沒人加過鎖,那麼state的值肯定是0,此時執行緒1就可以加鎖成功。
一旦執行緒1加鎖成功了之後,就可以設定當前加鎖執行緒是自己。所以大家看下面的圖,就是執行緒1跑過來加鎖的乙個過程。
其實看到這兒,大家應該對所謂的aqs有感覺了。說白了,就是並發包裡的乙個核心元件,裡面有state變星、加鎖執行緒變數等核心的東西,維護了加鎖狀態。
你會發現,reentrantlock這種東西只是乙個外層的api,核心中的鎖機制實現都是依賴aqs元件的。這個reentrantlock之所以用reentrant打頭,意思就是他是乙個可重入鎖。
可重入鎖的意思,就是你可以對乙個reentrantlock物件多次執行lock)加鎖和unlock()釋放鎖,也就是可以對乙個鎖加多次,叫做可重入加鎖。
大家看明白了那個state變數之後,就知道了如何進行可重入加鎖!
其實每次執行緒1可重入加鎖一次,會判斷一下當前加鎖執行緒就是自己,那麼他自己就可以可重入多次加鎖,每次加鎖就是把state的值給累加1,別的沒啥變化。
接著,如果執行緒1加鎖了之後,執行緒2跑過來加鎖會怎麼樣呢?
我們來看看鎖的互斥是如何實現的?執行緒2跑過來一下看到,哎呀! state的值不是o啊?所以cas操作將state從0變為1的過程會失敗,因為state的值當前為1,說明已經有人加鎖了!
接著執行緒2會看一下,是不是自己之前加的鎖啊?當然不是了,「加鎖執行緒"這個變數明確記錄了是執行緒1占用了這個鎖,所以執行緒2此時就是加鎖失敗。
給大家來一張圖,一起來感受—下這個過程:
所以大家可以看到,aqs是如此的核心!aqs內部還有乙個等待佇列,專門放那些加鎖失敗的執行緒!同樣,給大家來一張圖,一起感受—下:
如圖整個過程
好!執行緒2現在就重新嘗試加鎖,這時還是用cas操作將state從0變為1,此時就會成功,成功之後代表加鎖成功,就會將state設定為1。
此外,還要把"加鎖執行緒"設定為執行緒2自己,同時執行緒2自己就從等待佇列**隊了。最後再來—張圖,大家來看看這個過程。
總而言之,其實一句話總結aqs就是乙個並發包的基礎元件,用來實現各種鎖,各種同步元件的。它包含了state變數、加鎖執行緒、等待佇列等併發中的核心元件。
aqs 使用了模板方法模式,自定義同步器時需要重寫下面幾個 aqs 提供的模板方法:
---- 以 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(compare and swap)減 1。等到所有子執行緒都執行完後(即 state=0),會 unpark()主呼叫執行緒,然後主呼叫執行緒就會從 await()函式返回,繼續後余動作。
----一般來說,自定義同步器要麼是獨佔方法,要麼是共享方式,他們也只需實現tryacquire-tryrelease
、tryacquireshared-tryreleaseshared
中的一種即可。但 aqs 也支援自定義同步器同時實現獨佔和共享兩種方式,如reentrantreadwritelock
。
java併發 重入鎖 ReentrantLock
使用 github主頁 重入鎖,標識在乙個執行緒中,可重複對該資源重複加鎖。針對於aqs實現重入功能 在重寫tryaquires 的時候考慮同乙個執行緒多次lock的情況即可 偽 thread currentthread thread.currentthread getexclusiveownert...
顯式鎖和AQS
實現鎖的關鍵在於 通過cas操作與volatile變數互相配合,執行緒安全的修改鎖標誌位 基於clh佇列,實現鎖的排隊策略,對於公平鎖,當前執行緒只需要監控他的前驅節點的鎖情況,當前鎖持有這肯定是頭節點 個人理解記錄 reentrantlock基於aqs實現,他的基本原理是aqs的status為0時...
顯式鎖和AQS
lock介面和核心方法 lock介面和synchronized的比較 synchronized 簡潔,lock 獲取鎖可以被中斷,超時獲取鎖,嘗試獲取鎖,讀多寫少用讀寫鎖 可重入鎖reentrantlock 所謂鎖的公平和非公平 如果在時間上,先對鎖進行獲取的請求,一定先被滿足,這個鎖就是公平的,不...