JVM09 Java虛擬機是如何實現synchronized的?

synchronized--面試的熱點問題了吧,用法大家都知道:可以作用在代碼塊、靜態方法、實例方法,也知道三種用法鎖的對象是啥,底層原理是什么呢?虛擬機是如何實現的呢?

先看一段被synchronized聲明的代碼塊編譯后的字節碼。

public void foo(Object lock) {
    synchronized (lock) {
      lock.hashCode();
    }
  }
// 上面的 Java 代碼將編譯為下面的字節碼
 public void foo(java.lang.Object);
    Code:
       0: aload_1
       1: dup
       2: astore_2
       3: monitorenter
       4: aload_1
       5: invokevirtual java/lang/Object.hashCode:()I
       8: pop
       9: aload_2
      10: monitorexit
      11: goto          19
      14: astore_3
      15: aload_2
      16: ***monitorexit***
      17: aload_3
      18: athrow
      19: return
    Exception table:
       from    to  target type
           4    11    14   any
          14    17    14   any

字節碼的每行意思暫且不研究,會發現很醒目的三行命令,第3行的monitorenter,第10行和第16行的monitorexit。當聲明 synchronized 代碼塊時,編譯而成的字節碼將包含 monitorenter 和 monitorexit 指令。這兩種指令均會消耗操作數棧上的一個引用類型的元素(也就是 synchronized 關鍵字括號里的引用),作為所要加鎖解鎖的鎖對象。

聲明方法時的字節碼

public synchronized void foo(Object lock) {
    lock.hashCode();
  }
  // 上面的 Java 代碼將編譯為下面的字節碼
  public synchronized void foo(java.lang.Object);
    descriptor: (Ljava/lang/Object;)V
    flags: (0x0021) ACC_PUBLIC, ACC_SYNCHRONIZED
    Code:
      stack=1, locals=2, args_size=2
         0: aload_1
         1: invokevirtual java/lang/Object.hashCode:()I
         4: pop
         5: return

你會看到字節碼中方法的訪問標記包括 ACC_SYNCHRONIZED,這里 monitorenter 和 monitorexit 操作所對應的鎖對象是隱式的。對于實例方法來說,這兩個操作對應的鎖對象是 this;對于靜態方法來說,這兩個操作對應的鎖對象則是所在類的 Class 實例。

講到這里插入一個Jvm中對象的概念:對象的內存布局
對象在內存中的布局可以分為3塊區域:對象頭(header),實例數據(Instance Data)和對齊填充(Padding)。
對象頭包括兩部分信息:
第一部分用于存儲對象自身的運行時數據。如哈希碼,GC分代年齡,鎖狀態標志,線程持有的鎖,偏向線程id,偏向時間戳等??紤]到虛擬機的空間效率,此部分在32位和64位虛擬機中只占32位或者64位的大小。
第二部分是類型指針。即對象指向它的類元數據的指針,虛擬機通過這個指針來確定這個對象是哪個類的實例。(并不是所有的虛擬機實現都保留類型指針,查找對象的元數據信息不一定要通過對象本身)
如果該對象是數組,那么對象頭還會保留一塊數據,用于記錄數組長度。

很多文章都講到synchronized底層是對象頭+monitor實現的,沒錯,那具體是怎么實現的呢?
對象頭的作用就是提供鎖計數器和指向線程的指針的
當執行 monitorenter 時,如果計數器為 0,說明沒有被其他線程所持有。Java 虛擬機會將該鎖對象的持有線程指向當前線程,并且將其計數器加 1;如果計數器的值不為0,先判斷指針指向是否是當前線程,若是則可獲取鎖(可重入鎖),并且計數器加1,若不是則進入阻塞狀態
當執行 monitorexit 時,Java 虛擬機則需將鎖對象的計數器減 1。當計數器減為 0 時,那便代表該鎖已經被釋放掉了。
為什么上面字節碼中出現兩次 monitorexit?那是考慮到異常情況也要釋放鎖。

自JDK1.5之后就對synchronized做了很大的優化,加入了自旋鎖,輕量級鎖,偏向鎖等

重量級鎖

Java 虛擬機中最為基礎的鎖實現。在這種狀態下,Java 虛擬機會阻塞加鎖失敗的線程,并且在目標鎖被釋放的時候,喚醒這些線程。
缺點:Java 線程的阻塞以及喚醒,都是依靠操作系統來完成的,這些操作將涉及系統調用,需要從操作系統的用戶態切換至內核態,其開銷非常之大。

自旋鎖

為了盡量避免昂貴的線程阻塞、喚醒操作,Java 虛擬機會在線程進入阻塞狀態之前,以及被喚醒后競爭不到鎖的情況下,進入自旋狀態,在處理器上空跑并且輪詢鎖是否被釋放。如果此時鎖恰好被釋放了,那么當前線程便無須進入阻塞狀態,而是直接獲得這把鎖。
缺點:很明顯,自旋占用cup資源,在高并發的情況下很影響系統性能。

輕量級鎖

采用 CAS 操作,將鎖對象的標記字段替換為一個指針,指向當前線程棧上的一塊空間,存儲著鎖對象原本的標記字段。它針對的是多個線程在不同時間段申請同一把鎖的情況。

偏向鎖

只會在第一次請求時采用 CAS 操作,在鎖對象的標記字段中記錄下當前線程的地址。在之后的運行過程中,持有該偏向鎖的線程的加鎖操作將直接返回。它針對的是鎖僅會被同一線程持有的情況。

網上很多文章還在說synchronized的性能不如lock,那是以前,現在看來synchronized的性能會更好,當然考慮到synchronized是非公平鎖,無法手動釋放,沒有讀寫分離功能還是要選擇lock。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 227,882評論 6 531
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,208評論 3 414
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事?!?“怎么了?”我有些...
    開封第一講書人閱讀 175,746評論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,666評論 1 309
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,477評論 6 407
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 54,960評論 1 321
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,047評論 3 440
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,200評論 0 288
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,726評論 1 333
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,617評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,807評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,327評論 5 358
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,049評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,425評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,674評論 1 281
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,432評論 3 390
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,769評論 2 372

推薦閱讀更多精彩內容