1. 程式人生 > >從Java的物件頭到Java內建鎖synchronized的底層實現(一)

從Java的物件頭到Java內建鎖synchronized的底層實現(一)

        就如標題,今天我們的話題會從物件說起。我們知道物件在JVM的記憶體結構中,是存放在堆記憶體中的(new  一個類之後JVM會在堆上為new出的物件申請一塊空間)。在記憶體中,一個Java物件包含三部分:物件頭、例項資料和對齊填充。而物件頭記憶體有的資訊就有mark work,這是實現synchronized鎖機制的核心。物件頭到底是什麼呢?是怎樣通過物件頭來實現synchronized鎖機制呢?這就是這篇部落格所要描述的事了。

        首先我看看如下程式碼,(以下程式碼就是物件頭的描述)

class oopDesc {
  friend class VMStructs;
 private:
  volatile markOop  _mark;
  union _metadata {
    wideKlassOop    _klass;
    narrowOop       _compressed_klass;
  } _metadata;
}

我們可以看到物件頭的描述中有一個友元類,有_mark,還發現了一個在學習  synchronized(內建鎖)反覆被提到的東西 _mark(也就是常說的mark  word)。其中

mark work

mark work用於儲存物件自身的執行時資料,如雜湊碼(HashCode)、GC分代年齡、鎖狀態標誌、執行緒持有的鎖、偏向執行緒ID、偏向時間戳等等,佔用記憶體大小與虛擬機器位長一致。

型別指標

型別指標指向物件的類元資料,虛擬機器通過這個指標確定該物件是哪個類的例項。

        在mark work中就有好多欄位是關於synchronized(內建鎖)的實現。     我們可以深入的看一看mark  word的型別markOop是怎麼描述的。下面是mark word 存有的資訊。

(網上查詢)

我們知道Java是一個優化做的很好的語言,我們可以看到mark work中儲存資訊是分情況,相對不同的鎖是儲存不同的資訊的。所以Java利用這一點先確定是那種鎖再動態的分配位元位去儲存資訊,已達到節省空間的效果。也就是說這時一個非固定的資料結構,利用物件的鎖狀態來賦予位元位不同的含義。因為一個物件在一個時刻只會有一種鎖狀態,所以在這個時刻時在32位機上就只用32位,也就是四個位元組就可以儲存完資訊。

       以上就是我對markwork的初步瞭解。下面是關於synchronized鎖機制的實現。

       物件的鎖到底是什麼呢?應該怎樣理解?系統又是怎樣實現的呢?我的理解是對物件的一個標誌,也就是物件的物件頭中markword所儲存的資訊。這也就可以理解為什麼synchronized鎖是加在物件上的,而不是加在程式碼上了,原因是它本身就是物件頭裡markword中記錄的一個標誌,反映給使用者就是所說的物件鎖。

       我們從上表看到鎖狀態的表示

 無鎖                         (001)     

 偏向鎖                     (101)

 輕量級鎖                 (00)

 重量級鎖                 (10)(阻塞式實現,會把沒有競爭到鎖的執行緒掛起,在合適的時候恢復,而這些操作是要經過核心態處理的,會給系統的併發性造成很大的壓力)

這個從上到下的排列也就是鎖從輕量到重量的一個過程。偏向鎖在JDK6後預設啟動,有需要的條件下重量級會逐漸升高(這是一種優化)。

重量級升高的過程這涉及到synchronized鎖的優化,後面我會用一整篇來描述我的理解。