一、Synchronization原理分析
Synchronization 鎖原理是對象同步通過Monitor 來實現的,java每個對象都會有Monitor鎖標記,代碼塊同步使用的是MONITORENTER和MONITOREXIT來同步;類似於操作系統的PV操作,MONITORENTER會執行+1操作,而MONITOREXIT會執行-1操作。
二、Synchronization數據存放格式
2.1、數據存放
Synchronization存放在對象的頭部,總共有兩種類型,分別是對象和數組類型,不同的類型存放的格式有所差異,普通對象類型暫用3字寬,數組類型佔用2字寬,1字寬=4字節=32bit(32位虛擬機),鎖只能升級不能降級,如下圖,偏向鎖升級爲輕量級鎖之後不能在降級爲偏向鎖了。
鎖狀態 | 25bit | 4bit | 1bit | 2bit | |
---|---|---|---|---|---|
23bit | 2bit | 是否是偏向鎖 | 鎖標誌位 | ||
無鎖狀態 | 對象hashCode | 對象分代年齡 | 0 | 01 | |
輕量級鎖 | 指向棧中鎖記錄的指針 | 00 | |||
重量級鎖 | 指向互斥量的指針 | 10 | |||
GC標記 | 空 | ||||
偏向鎖 | 線程ID | Epoch | 對象分代年齡 | 1 | 01 |
2.2、偏向鎖
從數據結構中可以看出,記錄當前線程訪問的ID,如果同一個線程訪問同一個同步塊時,減少加鎖和解鎖操作,直接使用同步快就可以了,降低了獲取鎖和加鎖的開銷。
偏向鎖不會主動撤銷鎖,只有當其他線程競爭資源的時候纔會釋放鎖,變成無鎖狀態,變成爲無鎖狀態需要當先線程已經執行完了同步塊,否則競爭線程會需要等待資源釋放。一旦鎖資源釋放,會喚醒競爭等待的線程。
偏向鎖調整相關參數設置,關閉延遲:-XX:BiasedLockingStartUpDelay=0;關閉偏向鎖:-XX:UseBiasedLocking=true
2.3、輕量級鎖
加鎖:(1)在當前線程棧幀空間創建存儲對象頭MarkWord空間;(2)複製對象MarkWord至(1)創建的空間;(3)使用CAS操作將對象頭中的MarkWord替換爲指向當前線程所記錄的指針,成功表示獲取鎖,失敗表示爲獲取到鎖。
解鎖:使用CAS將當前線程的棧幀中保存的MarkWord替換,回到原來的對象頭,如果成功,表示當前沒有競爭資源失敗會自旋重新獲取,超過一定閾值之後,會升級爲重量級鎖,輕量級鎖升級爲重量級鎖之後,沒法在降級爲輕量級鎖了。
2.3、重量級鎖
有輕量級鎖升級爲重量鎖,其鎖保存了互斥量的指針,並且會阻塞當前線程,當一旦有鎖釋放之後,會喚醒當前阻塞的線程。
2.4、性能場景比較
鎖名稱 | 優點 | 缺點 |
---|---|---|
偏向鎖 | 單個線程獲取鎖無需加鎖和解鎖步驟,降低加鎖和解鎖開銷、使用一個線程多次訪問同步 | 多個線程或存在鎖競爭,多一個鎖撤銷開銷 |
輕量級鎖 | 競爭線程不會阻塞,響應速度快 | 自旋會消耗CPU資源 |
重量級鎖 | 吞吐量高 | 線程阻塞,響應時間慢 |