無鎖、偏向鎖、輕量級鎖、重量級鎖
以下為32位元物件頭描述
以下為64位元物件頭描述
當執行緒存取同步程式碼塊時,首先判斷當前鎖狀態是否為可偏向狀態(物件頭中偏向鎖=1,鎖標誌=01)在JDK1.6以上預設開啟,開啟後程式啟動幾秒後才會被啟用
如果是可偏向狀態,檢查MarkWord儲存的是否是當前執行緒ID
升級為輕量級鎖的情況
加鎖時,會在當前執行緒棧幀中劃出一塊空間,作為該鎖記錄,並且將鎖物件MarkWord複製到該鎖記錄中,CAS操作將MarkWord更新為該鎖記錄的指標,鎖記錄中的owner指標指向物件頭的MarkWord。
升級為重量級鎖的情況
獲取鎖成功,進入EntryList(獲取鎖的緩衝區、入口)
具體重量級鎖加鎖過程:
1、分配⼀個ObjectMonitor物件,把MarkWord鎖標誌置為‘10’,然後MarkWord儲存指向ObjectMonitor物件的指標。ObjectMonitor物件有兩個佇列和⼀個指標,每個需要獲取鎖的執行緒都包裝成ObjectWaiter物件
2、多個執行緒同時執行同⼀段同步程式碼時,ObjectWaiter先進⼊EntryList佇列,當某個執行緒獲取到物件的monitor以後進⼊Owner區域,並把monitor中的owner變數設定為當前執行緒,同時monitor中的計數器count+1
說明:
monitor:每個Java物件都有一把鎖,稱為內部鎖或monitor鎖
owner,指向的是當前獲得執行緒的地址,用來判斷當前鎖是被哪個執行緒持有
使用者態:偏向鎖、輕量級鎖
核心態:重量級鎖
首先來了解下synchronized重量級鎖實現原理?
通過物件內部的一個叫做監視器鎖(monitor)來實現的,監視器鎖本質又是依賴於底層的作業系統的 Mutex Lock(互斥鎖)來實現的。而作業系統實現執行緒之間的切換需要從使用者態轉換到核心態,這個成本非常高。
在JDK6以前,只有重量級鎖,阻塞或喚醒一個Java執行緒需要作業系統切換CPU狀態來完成,這種狀態切換需要耗費處理器時間。
在JDK6中,為了提高效能,引入了偏向鎖和輕量級鎖。
大多數情況下,鎖不僅不存在多執行緒競爭,而且總是由同一執行緒多次獲得,為了減少執行緒獲得鎖的代價,所以引入了偏向鎖
自旋鎖消耗CPU資源,重量級鎖有等待佇列,不會消耗CPU資源
不一定,在多執行緒競爭情況下,偏向鎖會涉及鎖復原,這時候應該直接使用自旋鎖
重入次數必須記錄,才能知道要解鎖幾次
不是的,Hopspot物件頭主要包括兩部分資料:MarkWord(標記欄位) 和 classPointer(類指標)
不行的,是一個不可逆的過程,主要是為了提高獲得鎖和釋放鎖的效率
偏向鎖:適用於一個執行緒,不會有鎖消耗,鎖復原
輕量級鎖:適用於多個執行緒競爭,但同步程式碼塊執行快的情況下,因為自旋會消耗CPU
重量級鎖:適用於多個執行緒競爭,但同步程式碼塊執行慢的情況下,不消耗CPU,可以提高吞吐量