Java synchronized重量級鎖實現過程淺析

一、什麼是重量級鎖

當有大量的線程都在競爭同一把鎖的時候,這個時候加的鎖,就是重量級鎖。

這個重量級鎖其實指的就是JVM內部的ObjectMonitor監視器對象:

ObjectMonitor() {
    _header       = NULL;		//鎖對象的原始對象頭
    _count        = 0;			//搶占當前鎖的線程數量
    _waiters      = 0,			//調用wait方法後等待的線程數量
    _recursions   = 0;			//記錄鎖重入次數
    _object       = NULL;
    _owner        = NULL;		//指向持有ObjectMonitor的線程
    _WaitSet      = NULL;		//處於wait狀態的線程隊列,等待被喚醒
    _WaitSetLock  = 0 ;
    _Responsible  = NULL ;
    _succ         = NULL ;
    _cxq          = NULL ;
    FreeNext      = NULL ;
    _EntryList    = NULL ;		//等待鎖的線程隊列
    _SpinFreq     = 0 ;
    _SpinClock    = 0 ;
    OwnerIsThread = 0 ;
    _previous_owner_tid = 0;
  }

二、重量級鎖的演示

public class HightweightLockDemo02 {
    public static void main(String[] args) {
        Object objLock = new Object();
        new Thread(() -> {
            synchronized (objLock) {
                System.out.println(ClassLayout.parseInstance(objLock).toPrintable());
            }
        }, "t1").start();
        new Thread(() -> {
            synchronized (objLock) {
                System.out.println(ClassLayout.parseInstance(objLock).toPrintable());
            }
        }, "t2").start();
    }
}

運行程序:

java.lang.Object object internals:
 OFFSET  SIZE   TYPE DESCRIPTION                               VALUE
      0     4        (object header)                           1a 33 c9 e1 (00011010 00110011 11001001 11100001) (-506907878)
      4     4        (object header)                           43 01 00 00 (01000011 00000001 00000000 00000000) (323)
      8     4        (object header)                           e5 01 00 f8 (11100101 00000001 00000000 11111000) (-134217243)
     12     4        (loss due to the next object alignment)
Instance size: 16 bytes
Space losses: 0 bytes internal + 4 bytes external = 4 bytes total
java.lang.Object object internals:
 OFFSET  SIZE   TYPE DESCRIPTION                               VALUE
      0     4        (object header)                           1a 33 c9 e1 (00011010 00110011 11001001 11100001) (-506907878)
      4     4        (object header)                           43 01 00 00 (01000011 00000001 00000000 00000000) (323)
      8     4        (object header)                           e5 01 00 f8 (11100101 00000001 00000000 11111000) (-134217243)
     12     4        (loss due to the next object alignment)
Instance size: 16 bytes
Space losses: 0 bytes internal + 4 bytes external = 4 bytes total

可見,當多個線程共同搶占同一把鎖的時候,鎖對象MarkWord的最後三位是“010”,代表的就是一個重量級鎖。

三、重量級鎖的原理

以上述代碼為例,synchronized獲取的鎖是重量級鎖,synchronized修飾代碼塊,使用javap -p -v .\HightweightLockDemo02.class指令查看其字節碼:

在編譯的時候,JVM會在同步塊開始位置插入monitorenter指令,在同步塊結束位置插入monitorexit指令。當線程執行到monitorenter指令時,會嘗試獲取對象所對應的Monitor所有權,如果獲取成功,則表示獲取到瞭鎖,會在Monitor的_owner中存在當前線程的ID,這樣它將處於鎖定狀態,除非退出同步塊,否則其他線程無法獲取得到這個Monitor。

四、鎖的優缺點對比

下表是對各種狀態的鎖的對比:

鎖的類型 優點 缺點 適用場景
偏向鎖 加鎖和解鎖不需要額外的消耗,和執行非同步方法相比僅存在納秒級的差距 如果線程間存在鎖競爭,會帶來額外的鎖撤銷的消耗 適用於隻有一個線程訪問同步塊場景
輕量級鎖 競爭的線程不會阻塞,提高瞭程序的響應速度 如果始終得不到鎖競爭的線程,使用自旋會消耗CPU,導致CPU空轉 追求響應時間 同步塊執行速度非常快
重量級鎖 線程競爭不使用自旋,不會消耗CPU 線程阻塞,響應時間緩慢 追求吞吐量 同步塊執行時間較長

到此這篇關於Java synchronized重量級鎖實現過程淺析的文章就介紹到這瞭,更多相關Java synchronized 內容請搜索WalkonNet以前的文章或繼續瀏覽下面的相關文章希望大傢以後多多支持WalkonNet!

推薦閱讀: