1. 程式人生 > 實用技巧 >Syncronized之偏向鎖

Syncronized之偏向鎖

  介紹偏向鎖之前,先熟悉一下物件在堆中的資料結構。陣列需要有一塊區域表示陣列的長度,物件和陣列的結構是有區別的。

  物件主要分為物件頭、物件中實際的資料和對齊填充。陣列分為物件頭、陣列中的元素和對齊填充,陣列的長度在物件頭中儲存,圖示如下:

  

  

Mark Word:預設儲存物件的HashCode,分代年齡和鎖標誌位資訊。這些資訊都是與物件自身定義無關的資料,所以Mark Word被設計成一個非固定的資料結構以便在極小的空間記憶體儲存儘量多的資料。
      它會根據物件的狀態複用自己的儲存空間,也就是說在執行期間Mark Word裡儲存的資料會隨著鎖標誌位的變化而變化。 Class Pointer:物件指向它的類元資料的指標,虛擬機器通過這個指標來確定這個物件是哪個類的例項。

   下圖是32虛擬機器表示的不同鎖的狀態下Mark Word中的資料結構 。

  

  • 無狀態也就是無鎖的時候,物件頭開闢 25bit 的空間用來儲存物件的 hashcode ,4bit 用於存放分代年齡,1bit 用來存放是否偏向鎖的標識位,2bit 用來存放鎖標識位為01
  • 偏向鎖 中劃分更細,還是開闢25bit 的空間,其中23bit 用來存放執行緒ID,2bit 用來存放 epoch,4bit 存放分代年齡,1bit 存放是否偏向鎖標識, 0表示無鎖,1表示偏向鎖,鎖的標識位還是01
  • 輕量級鎖中直接開闢 30bit 的空間存放指向棧中鎖記錄的指標,2bit 存放鎖的標誌位,其標誌位為00
  • 重量級鎖中和輕量級鎖一樣,30bit 的空間用來存放指向重量級鎖的指標,2bit 存放鎖的標識位,為11
  • GC標記開闢30bit 的記憶體空間卻沒有佔用,2bit 空間存放鎖標誌位為11。

  偏向鎖

  偏向鎖目的是清除資料在無競爭情況下的同步,進一步提高程式的執行效能。輕量級鎖是在無競爭的情況下使用CAS操作去清除同步使用的互斥量,而偏向鎖是在無競爭情況下把整個同步都清除掉,連CAS都不做了。

  獲取過程:當鎖物件第一次被執行緒獲取的時候,虛擬機器將會把物件頭中的鎖標誌位設為01,同時使用CAS操作把獲取到這個鎖的執行緒ID記錄到物件的Mark Word中,如果CAS操作成功,持有偏向鎖的執行緒以後每次進入這個鎖相關的同步塊時,虛擬機器都可以不進行任何同步操作。

  釋放過程:當有另外一個執行緒去嘗試獲取這個鎖時,偏向鎖就宣告結束,升級為輕量級鎖。

  輕量級鎖

  “輕量級”是相對於傳統的使用互斥量來實現的傳統鎖而言的,因此傳統的鎖機制就被稱為“重量級鎖”。

  獲取過程:程式碼進入同步塊的時候,如果此同步物件沒有被鎖定(鎖標示為01狀態),虛擬機器將使用CAS操作嘗試將物件的Mark Work更新為指向Lock Record的指標。如果更新成功,那麼這個想成就擁有了這個物件的鎖,並且將鎖標識位變為00,如果更新失敗了,虛擬機器首先會檢查物件的Mark Word是否指向當先執行緒的棧幀,如果是說明當前執行緒已經擁有了這個物件的鎖,那就可以直接進入同步塊繼續執行,否則說明這個執行緒已經被其他執行緒搶佔了。

  釋放過程:如果有兩條以上的執行緒同時競爭同一把鎖,那麼輕量級鎖就不在有效,膨脹為重量級鎖,鎖的標識位變為10。