Synchronized鎖原理
前情提要
-
對於普通同步方法,鎖是當前實例對象。
-
對於靜態同步方法,鎖是當前類的Class對象。
-
對於同步方法塊,鎖是Synchonized括號裏配置的對象。
Synchonized在JVM裏的實現原理,
JVM基於進入和退出Monitor對 象來實現方法同步和代碼塊同步
Monitor是有monitorenter和monitorexit指令的,線程每次執行到monitorenter,都會嘗試獲取對象的monitor,也就是對象的鎖
鎖的升級
Java對象頭裏的Mark Word裏默認存儲對象的HashCode、分代年齡和鎖標記位。
無鎖狀態、偏向鎖狀態、輕量級鎖狀態和重量級鎖狀態,這幾個狀態會隨着競爭情況逐漸升級。鎖可以升級但不能降級
1. 偏向鎖
爲什麼有偏向鎖概念?
爲了減少獲得鎖和釋放鎖帶來的性能消耗.
那下面來從減少消耗入手來講
大多數情況下,鎖不僅不存在多線程競爭,而且總是由同 一線程多次獲得,爲了讓線程獲得鎖的代價更低而引入了偏向鎖
你可以理解可重入鎖,當進入拿到了鎖再進入其它的就方便了,這裏只是比喻。。不等同
哪些措施減少消耗的(線程ID的檢查)
當一個線程訪問同步塊並 獲取鎖時,會在對象頭和棧幀中的鎖記錄裏存儲鎖偏向的線程ID,下次進入直接測試有無ID記錄,有就簡單了直接盤它!
沒有的話,先看看這是不是偏向鎖,不是就用CAS競爭鎖然後記錄線程ID,是的話就用CAS直接記錄自己的線程ID,
1.1 偏向鎖的撤銷
只要有其它線程競爭偏向鎖,就會釋放鎖,具體流程如下:
線程1拿到偏向鎖在執行,線程2來執行同步方法,先檢查ID,沒有,檢查發現是偏向鎖,CAS記錄自己的線程ID,但在記錄之前需要暫停線程1,然後把線程ID設置爲空,然後就可以設置自己的了
1.2 偏向鎖的意義
偏向鎖,它的目的是消除數據在無競爭的情況下的同步原語,進一步提高程序的運行性能,不用CAS
2. 輕量級鎖
2.1 加鎖
-
線程在執行同步塊之前,JVM會先在當前線程的棧楨中創建用於存儲鎖記錄的空間
-
拿到鎖記錄指針。將對象頭中的Mark Word複製到鎖記錄中,CAS替換那個markword
-
如果成功,當前線程獲得鎖,
-
如果失敗,表示其他線程競爭鎖,當前線程便嘗試使用自旋來獲取鎖。
2.2 解鎖
-
輕量級解鎖時,會使用原子的CAS操作將Displaced Mark Word替換回到對象頭
-
如果成功,則表示沒有競爭發生。
-
如果失敗,表示當前鎖存在競爭,鎖就會膨脹成重量級鎖
2.3 輕量鎖的意義
輕量級鎖是在無競爭的情況下使用CAS操作去消除同步使用的互斥量
3.鎖的對比
鎖 | 優點 | 缺點 | 使用場景 |
---|---|---|---|
偏向鎖 | 加鎖和解鎖無消耗,爭取不用CAS | 競爭鎖的情況會有撤銷鎖的消耗 | 適用單線程 |
輕量級鎖 | 競爭的線程不會阻塞,利用CAS | CAS會自旋消耗CPU | 追求響應時間 |
重量級鎖 | 不會消耗CPU,直接阻塞對方 | 線程會阻塞 | 追求吞吐量,不在乎時間和交互 |