目錄
一、如何形容 synchronized 鎖
二、鎖升級
2.1 偏向鎖
2.2 輕量級鎖
2.3 重量級鎖
三、鎖消除
四、鎖粗化
一、如何形容 synchronized 鎖
synchronized 鎖是一個內部優化非常好的鎖,大部分情況下這個鎖都是適用的。 |
在初始階段 synchronized 是一個樂觀鎖、輕量級鎖、自旋鎖,隨著鎖沖突變得更激烈,synchronized 會轉換為悲觀鎖、重量級鎖、掛起等待鎖。 |
與此同時,synchronized 還是一個可重入鎖、非公平鎖、非讀寫鎖。 |
二、鎖升級
synchronized 的加鎖過程 | |||
無鎖 | 偏向鎖 | 輕量級鎖 | 重量級鎖 |
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> | |||
JVM 將 synchronized 鎖分為 以上四個階段,會根據實際情況,對鎖進行升級。應該注意的是,目前所只能升級,不能降級。 |
2.1 偏向鎖
階段描述: |
當鎖第一次被一個線程獲取時,優先進入偏向鎖狀態。 |
偏向鎖并非真的“加鎖”,而是在對象頭中做一個“偏向鎖標記”,記錄該鎖屬于哪個線程。 |
如果后續沒有其他線程競爭該鎖,那么該鎖不會有后續升級操作,減少了加鎖帶來的系統開銷。 |
如果后續有其他線程競爭該鎖,那么鎖會真正的加鎖,升級為輕量級鎖。由于之前已經記錄了該鎖屬于哪個線程,所以此時鎖也是被記錄的線程獲取的。 |
這種升級操作實際上屬于延遲加鎖,不必要不加鎖,減少了加鎖的系統開銷,提高了運行效率。 |
2.2 輕量級鎖
階段描述: |
隨著鎖競爭的開始,鎖將進入輕量級鎖的狀態,在初始狀態是通過自旋鎖實現的。 |
自旋鎖是循環不斷地讓線程嘗試獲取鎖。優點在于當鎖被釋放,其他線程可以第一時間獲取到鎖。 |
而自旋鎖的缺點也在于會一直占用CPU資源。synchronized 對此也進行了優化,當自旋達到一定的時間或次數時,就不再自旋了,將轉換為掛起等待。 |
同時,synchronized 內部也會統計當前鎖對象有多少線程在競爭,如果鎖競爭更加激烈,synchronized 就會從輕量級鎖升級為重量級鎖。 |
2.3 重量級鎖
階段描述: |
重量級鎖是指使用內核提供的 mutex 鎖。 |
mutex 鎖執行加鎖操作時,會先進入內核態,在內核態判定當前鎖是否已經被占用。 |
如果該鎖沒有被占用,則加鎖成功,并切換回用戶態。 |
如果該鎖已經被占用,則加鎖失敗,線程阻塞等待,直到下一次喚醒。 |
三、鎖消除
什么是鎖消除? |
鎖消除是?synchronized 鎖的一種較保守的優化策略,通過編譯器和JVM判斷鎖是否可以消除。 |
這里的鎖消除只會處理一些直接可以判斷,完全不涉及線程安全問題的鎖,比如在單線程環境下使用 StringBuffer 類中的方法。 |
四、鎖粗化
什么是鎖粗化? |
這里有一個鎖的粒度的概念,可以這么認為:在鎖對象代碼塊中的代碼越少則認為鎖的粒度越細,反之則是越粗。 |
實際開發中,使用細粒度的鎖,往往是為了鎖可以被其他線程及時獲取。但有時,可能很長一段時間都沒用其他線程來競爭這個鎖。 |
因此,如果一段邏輯中出現多次加鎖解鎖,根據編譯器和JVM的判斷會自動對鎖進行粗化。 |
鎖粗化是指將多個細粒度的鎖合并為一個粗粒度的鎖,可以在特定場景下提高程序的執行效率,減小系統開銷。 |
閱讀指針 -> 《CAS編程及相關類》
鏈接生成中..........