知道synchronized原理嗎?

synchronized是java提供的原⼦性內建鎖,這種內建的並且使⽤者看不到的鎖也被稱為監視器鎖,使⽤synchronized之後,會在編譯之後在同步的程式碼塊前後加上monitorenter和monitorexit位元組碼指令,它依賴作業系統底層互斥鎖實現。它的作⽤主要就是實現原⼦性操作和解決共享變數的記憶體可⻅性問題。

執⾏monitorenter指令時會嘗試獲取物件鎖,如果物件沒有被鎖定或者已經獲得了鎖,鎖的計數器+1。此時其他競爭鎖的執行緒則會進⼊等待佇列中。執⾏monitorexit指令時則會把計數器-1,當計數器值為0時,則鎖釋放,處於等待佇列中的執行緒再繼續競爭鎖。

synchronized是排它鎖,當⼀個執行緒獲得鎖之後,其他執行緒必須等待該執行緒釋放鎖後才能獲得鎖,⽽且由於Java中的執行緒和作業系統原⽣執行緒是⼀⼀對應的,執行緒被阻塞或者喚醒時時會從⽤戶態切換到核心態,這種轉換⾮常消耗效能。

從記憶體語義來說,加鎖的過程會清除⼯作記憶體中的共享變數,再從主記憶體讀取,⽽釋放鎖的過程則是將⼯作記憶體中的共享變數寫回主記憶體。實際上⼤部分時候我認為說到monitorenter就⾏了,但是為了更清楚的描述,還是再具體⼀點。

如果再深⼊到原始碼來說,synchronized實際上有兩個佇列waitSet和entryList。

1. 當多個執行緒進⼊同步程式碼塊時,⾸先進⼊entryList

2. 有⼀個執行緒獲取到monitor鎖後,就賦值給當前執行緒,並且計數器+1

3. 如果執行緒調⽤wait⽅法,將釋放鎖,當前執行緒置為null,計數器-1,同時進⼊waitSet等待被喚醒,調⽤notify或者notifyAll之後⼜會進⼊entryList競爭鎖

4. 如果執行緒執⾏完畢,同樣釋放鎖,計數器-1,當前執行緒置為null

tags:#synchronized