1. 程式人生 > >偏向鎖、輕量級鎖、重量級鎖之間的變遷

偏向鎖、輕量級鎖、重量級鎖之間的變遷

物件鎖共有四種狀態:無鎖、偏向鎖、輕量級鎖、重量級鎖,鎖競爭程度依次加重。

物件鎖可以升級但不能降級,意味著偏向鎖升級成輕量級鎖後不能降級成偏向鎖。

自旋是一種獲取鎖的策略,存在於獲取輕量級鎖的過程中,不是一種鎖,java的物件鎖只有上述四種。

假設現在有一個物件O,剛剛被新建,處於無鎖狀態。此時執行緒A嘗試獲取物件鎖,如果此時jvm已經開啟了偏向鎖,那麼執行緒A會嘗試CAS操作將自己的執行緒Id寫入物件頭中的markword,並標記為偏向鎖,此時執行緒A成功獲取物件鎖,進入臨界區執行程式碼。當執行緒A退出臨界區時,並不會更改並釋放Mark Word中的偏向鎖記錄,而是繼續保留,當下一次執行緒A再次嘗試獲取物件鎖時,首先判斷當前物件鎖是否是偏向鎖,如果不是偏向鎖,說明此時物件鎖已經膨脹了,這種情況延後討論;如果是偏向鎖,只需簡單的測試Mark Word中的偏向鎖是否還是偏向自己即可,不需要額外的CAS操作。如果還是偏向自己,即Mark Word中的執行緒id是自己,那麼表示又成功獲取了鎖;如果不再偏向自己,而是其他執行緒,那麼首先會暫停擁有偏向鎖的執行緒,檢查此執行緒的狀態,如果不再存活,則將Mark Word標記為無鎖狀態,之後執行緒A再次競爭鎖即可;如果此執行緒還活著,那麼檢查此執行緒還是否需要持有鎖,如果需要繼續持有,那麼表明此時在有多個執行緒同時競爭偏向鎖,此時偏向鎖優勢不是很明顯,因此將偏向鎖升級為輕量級鎖(意思是,當此時持有鎖的執行緒釋放鎖後,之後的執行緒獲取到的鎖至少為輕量級鎖);如果不再需要繼續持有,即臨界區已經執行完成,那麼Mark Word標記為無鎖狀態,之後執行緒A再次競爭偏向鎖鎖即可。
接著上面偏向鎖膨脹的說,假設此時膨脹為了輕量級鎖,輕量級鎖從名字上理解,表明此時鎖競爭不是太大,因此當執行緒A使用CAS操作獲取輕量級鎖時,如果成功,那麼成功獲取到輕量級鎖;如果失敗,表明此時鎖存在競爭,但認為不是很嚴重,可能在很短的時間內鎖就會被其他執行緒釋放,此時如果將執行緒A變為阻塞狀態並釋放cpu時間片顯得成本有些大,因此執行緒A不釋放cpu時間片,會採用自旋的方式空轉一個週期,之後再嘗試CAS操作獲取輕量級鎖。自旋的次數會有一個閾值,如果在此閾值內獲取到了輕量級鎖,那麼jvm會動態上浮此閾值;如果在閾值次數內沒有獲取到輕量級鎖,意味著通過自旋獲取輕量級鎖失敗,此時輕量級鎖會膨脹為重量級鎖,此後執行緒獲取此物件鎖均為重量級鎖,意味著只要獲取不到鎖,執行緒就會進入阻塞狀態。