最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Java必會的Synchronized底層原理剖析

 更新時間:2022年10月19日 15:33:50   作者:一燈架構(gòu)  
synchronized作為Java程序員最常用同步工具,很多人卻對它的用法和實現(xiàn)原理一知半解,以至于還有不少人認為synchronized是重量級鎖,性能較差,盡量少用。但不可否認的是synchronized依然是并發(fā)首選工具,本文就來詳細講講

synchronized作為Java程序員最常用同步工具,很多人卻對它的用法和實現(xiàn)原理一知半解,以至于還有不少人認為synchronized是重量級鎖,性能較差,盡量少用。

但不可否認的是synchronized依然是并發(fā)首選工具,連volatile、CAS、ReentrantLock都無法動搖synchronized的地位。synchronized是工作面試中的必備技能,今天就跟著一燈一塊深入剖析synchronized的底層原理。

1. synchronized作用

synchronized是Java提供一種隱式鎖,無需開發(fā)者手動加鎖釋放鎖。保證多線程并發(fā)情況下數(shù)據(jù)的安全性,實現(xiàn)了同一個時刻只有一個線程能訪問資源,其他線程只能阻塞等待,簡單說就是互斥同步。

2. synchronized用法

先看一下synchronized有哪幾種用法?

使用位置被鎖對象示例代碼
實例方法實例對象public synchronized void method() {
……
}
靜態(tài)方法class類public static synchronized void method() {
……
}
實例對象實例對象public void method() {
Object obj = new Object();
synchronized (obj) {
……
}
}
類對象class類public void method() {
synchronized (Demo.class) {
……
}
}
this關(guān)鍵字實例對象public void method() {
synchronized (this) {
……
}
}

可以看到被鎖對象只要有兩種,實例對象和class類。

  • 由于靜態(tài)方法可以通過類名直接訪問,所以它跟直接加鎖在class類上是一樣的。
  • 當(dāng)在實例方法、實例對象、this關(guān)鍵字上面加鎖的時候,鎖定范圍都是當(dāng)前實例對象。
  • 實例對象上面的鎖和class類上面的鎖,兩者不互斥。

3. synchronized加鎖原理

當(dāng)我們使用synchronized在方法和對象上加鎖的時候,Java底層到底怎么實現(xiàn)加鎖的?

當(dāng)在類對象上加鎖的時候,也就是在class類加鎖,代碼如下:

/**
 * @author 一燈架構(gòu)
 * @apiNote Synchronized示例
 **/
public class SynchronizedDemo {

    public void method() {
        synchronized (SynchronizedDemo.class) {
            System.out.println("Hello world!");
        }
    }

}

反編譯一下,看一下源碼實現(xiàn):

可以看到,底層是通過monitorentermonitorexit兩個關(guān)鍵字實現(xiàn)的加鎖與釋放鎖,執(zhí)行同步代碼之前使用monitorenter加鎖,執(zhí)行完同步代碼使用monitorexit釋放鎖,拋出異常的時候也是用monitorexit釋放鎖。

寫成偽代碼,類似下面這樣:

/**
 * @author 一燈架構(gòu)
 * @apiNote Synchronized示例
 **/
public class SynchronizedDemo {

    public void method() {
        try {
            monitorenter 加鎖;
            System.out.println("Hello world!");
            monitorexit 釋放鎖;
        } catch (Exception e) {
            monitorexit 釋放鎖;
        }
    }

}

當(dāng)在實例方法上加鎖,底層是怎么實現(xiàn)的呢?代碼如下:

/**
 * @author 一燈架構(gòu)
 * @apiNote Synchronized示例
 **/
public class SynchronizedDemo {

    public static synchronized void method() {
        System.out.println("Hello world!");
    }

}

再反編譯看一下底層實現(xiàn):

這次只使用了一個ACC_SYNCHRONIZED關(guān)鍵字,實現(xiàn)了隱式的加鎖與釋放鎖。其實無論是ACC_SYNCHRONIZED關(guān)鍵字,還是monitorentermonitorexit,底層都是通過獲取monitor鎖來實現(xiàn)的加鎖與釋放鎖。

monitor鎖又是通過ObjectMonitor來實現(xiàn)的,虛擬機中ObjectMonitor數(shù)據(jù)結(jié)構(gòu)如下(C++實現(xiàn)的):

ObjectMonitor() {
    _header       = NULL;
    _count        = 0; // WaitSet 和 EntryList 的節(jié)點數(shù)之和
    _waiters      = 0,
    _recursions   = 0; // 重入次數(shù)
    _object       = NULL;
    _owner        = NULL; // 持有鎖的線程
    _WaitSet      = NULL; // 處于wait狀態(tài)的線程,會被加入到_WaitSet
    _WaitSetLock  = 0 ;
    _Responsible  = NULL ;
    _succ         = NULL ;
    _cxq          = NULL ; // 多個線程爭搶鎖,會先存入這個單向鏈表
    FreeNext      = NULL ;
    _EntryList    = NULL ; // 處于等待鎖block狀態(tài)的線程,會被加入到該列表
    _SpinFreq     = 0 ;
    _SpinClock    = 0 ;
    OwnerIsThread = 0 ;
  }

圖上展示了ObjectMonitor的基本工作機制:

  • 當(dāng)多個線程同時訪問一段同步代碼時,首先會進入 _EntryList 隊列中等待。
  • 當(dāng)某個線程獲取到對象的Monitor鎖后進入臨界區(qū)域,并把Monitor中的 _owner 變量設(shè)置為當(dāng)前線程,同時Monitor中的計數(shù)器 _count 加1。即獲得對象鎖。
  • 若持有Monitor的線程調(diào)用 wait() 方法,將釋放當(dāng)前持有的Monitor鎖,_owner變量恢復(fù)為null,_count減1,同時該線程進入 _WaitSet 集合中等待被喚醒。
  • 在_WaitSet 集合中的線程會被再次放到_EntryList 隊列中,重新競爭獲取鎖。
  • 若當(dāng)前線程執(zhí)行完畢也將釋放Monitor并復(fù)位變量的值,以便其他線程進入獲取鎖。

線程爭搶鎖的過程要比上面展示得更加復(fù)雜。除了_EntryList 這個雙向鏈表用來保存競爭的線程,ObjectMonitor中還有另外一個單向鏈表 _cxq,由兩個隊列來共同管理并發(fā)的線程。

以上就是Java必會的Synchronized底層原理剖析 的詳細內(nèi)容,更多關(guān)于Java Synchronized原理的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • 如何自定義MyBatis攔截器更改表名

    如何自定義MyBatis攔截器更改表名

    自定義MyBatis攔截器可以在方法執(zhí)行前后插入自己的邏輯,這非常有利于擴展和定制 MyBatis 的功能,本篇文章實現(xiàn)自定義一個攔截器去改變要插入或者查詢的數(shù)據(jù)源?,需要的朋友可以參考下
    2023-10-10
  • Java 類動態(tài)添加屬性字段的操作

    Java 類動態(tài)添加屬性字段的操作

    這篇文章主要介紹了Java 類動態(tài)添加屬性字段的操作,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2021-02-02
  • Java中的Comparable接口與Comparator接口區(qū)別解析

    Java中的Comparable接口與Comparator接口區(qū)別解析

    文章介紹了Java中的Comparable接口和Comparator接口,Comparable接口定義了一個compareTo方法,用于比較對象的順序,實現(xiàn)Comparable接口的類可以提供自然排序規(guī)則,詳細介紹了Java中的Comparable接口與Comparator接口區(qū)別,感興趣的朋友一起看看吧
    2025-02-02
  • Spring定時任務(wù)實現(xiàn)與配置(一)

    Spring定時任務(wù)實現(xiàn)與配置(一)

    這篇文章主要為大家詳細介紹了Spring定時任務(wù)的實現(xiàn)與配置第一篇,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2017-06-06
  • java連接hdfs ha和調(diào)用mapreduce jar示例

    java連接hdfs ha和調(diào)用mapreduce jar示例

    這篇文章主要介紹了Java API連接HDFS HA和調(diào)用MapReduce jar包,需要的朋友可以參考下
    2014-03-03
  • Java中IO流之字符流與字節(jié)流的轉(zhuǎn)換方式

    Java中IO流之字符流與字節(jié)流的轉(zhuǎn)換方式

    在Java中,字節(jié)流與字符流是處理數(shù)據(jù)的兩種方式,字節(jié)流適用于處理各種數(shù)據(jù)類型,如圖片、音頻等非文本數(shù)據(jù),而字符流專門用于處理文本數(shù)據(jù),Java提供了InputStreamReader和OutputStreamWriter這兩個類來實現(xiàn)字節(jié)流向字符流的轉(zhuǎn)換
    2024-10-10
  • Java正則表達式匹配不到結(jié)果的解決

    Java正則表達式匹配不到結(jié)果的解決

    這篇文章主要介紹了Java正則表達式匹配不到結(jié)果的解決,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2021-02-02
  • Java解析XML格式數(shù)據(jù)的方法詳解

    Java解析XML格式數(shù)據(jù)的方法詳解

    這篇文章主要介紹了Java解析XML格式數(shù)據(jù)的方法,并展示了較為常用的Java dom來解析XML的例子,需要的朋友可以參考下
    2015-10-10
  • Java數(shù)據(jù)結(jié)構(gòu)最清晰圖解二叉樹前 中 后序遍歷

    Java數(shù)據(jù)結(jié)構(gòu)最清晰圖解二叉樹前 中 后序遍歷

    樹是一種重要的非線性數(shù)據(jù)結(jié)構(gòu),直觀地看,它是數(shù)據(jù)元素(在樹中稱為結(jié)點)按分支關(guān)系組織起來的結(jié)構(gòu),很象自然界中的樹那樣。樹結(jié)構(gòu)在客觀世界中廣泛存在,如人類社會的族譜和各種社會組織機構(gòu)都可用樹形象表示
    2022-01-01
  • Spring中的PathVariable注釋解析

    Spring中的PathVariable注釋解析

    這篇文章主要介紹了Spring中的PathVariable注釋用法,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-10-10

最新評論

双辽市| 通城县| 铜梁县| 灌南县| 化州市| 罗甸县| 陕西省| 罗甸县| 铜鼓县| 高雄县| 邢台市| 应城市| 达孜县| 诏安县| 常宁市| 师宗县| 礼泉县| 吴川市| 奉新县| 金华市| 开封县| 太白县| 桐柏县| 故城县| 开阳县| 中阳县| 阿城市| 衡水市| 攀枝花市| 抚宁县| 黑水县| 马龙县| 吉水县| 宿松县| 车险| 辽阳市| 巫山县| 南和县| 哈密市| 苍溪县| 华亭县|