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

AQS加鎖機制Synchronized相似點詳解

 更新時間:2022年10月21日 11:38:51   作者:一燈架構(gòu)  
這篇文章主要為大家介紹了AQS加鎖機制Synchronized相似點詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪

正文

在并發(fā)多線程的情況下,為了保證數(shù)據(jù)安全性,一般我們會對數(shù)據(jù)進行加鎖,通常使用Synchronized或者ReentrantLock同步鎖。Synchronized是基于JVM實現(xiàn),而ReentrantLock是基于Java代碼層面實現(xiàn)的,底層是繼承的AQS。

AQS全稱 AbstractQueuedSynchronizer ,即抽象隊列同步器,是一種用來構(gòu)建鎖和同步器的框架。

我們常見的并發(fā)鎖ReentrantLock、CountDownLatchSemaphore、CyclicBarrier都是基于AQS實現(xiàn)的,所以說不懂AQS實現(xiàn)原理的,就不能說了解Java鎖。

當(dāng)我仔細研究AQS底層加鎖原理,發(fā)現(xiàn)竟然跟Synchronized加鎖原理有驚人的相似。讓我突然想到一句名言,記不清怎么說了,意思是框架底層原理很相似,大家多學(xué)習(xí)底層原理。

Synchronized的加鎖流程在前幾篇文章已經(jīng)詳細講過,沒看過一塊再溫習(xí)一下。

1. Synchronized加鎖流程

我們先想一下Synchronized的加鎖需求,如果讓你設(shè)計Synchronized對象鎖存儲結(jié)構(gòu),該怎么設(shè)計?

  • 多個線程執(zhí)行到Synchronized代碼塊,只有一個線程獲取鎖,然后執(zhí)行同步代碼塊(需要記錄哪個線程獲取了對象鎖)。
  • 其他線程被阻塞(被阻塞的線程,是不是可以用鏈表設(shè)計個阻塞隊列?)
  • 持有鎖的線程調(diào)用wait方法,釋放鎖,等待被喚醒(等待的線程,是不是可以用鏈表設(shè)計個等待隊列?)。
  • 被阻塞的線程開始競爭鎖
  • 調(diào)用notify方法,喚醒等待的線程,被喚醒的線程進入阻塞隊列,一塊競爭鎖。

上面描述了Synchronized的加鎖流程,Synchronized對象鎖存儲結(jié)構(gòu)是不是跟咱們想的一樣?實際就是的。

下面是對象鎖的存儲數(shù)據(jù)結(jié)構(gòu)(由C++實現(xiàn)):

ObjectMonitor() {
    _header       = NULL;
    _count        = 0;
    _waiters      = 0,
    _recursions   = 0;
    _object       = NULL;
    _owner        = NULL; // 持有鎖的線程
    _WaitSet      = NULL; // 等待隊列,存儲處于wait狀態(tài)的線程
    _WaitSetLock  = 0 ;
    _Responsible  = NULL ;
    _succ         = NULL ;
    _cxq          = NULL ;
    FreeNext      = NULL ;
    _EntryList    = NULL ; // 阻塞隊列,存儲處于等待鎖block狀態(tài)的線程
    _SpinFreq     = 0 ;
    _SpinClock    = 0 ;
    OwnerIsThread = 0 ;
  }

上圖展示了對象鎖的基本工作機制:

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

Synchronized對象鎖存儲結(jié)構(gòu)和加鎖流程,竟然跟咱們想的一樣。

再看一下ReentrantLock的存儲結(jié)構(gòu)和加鎖流程,有沒有相似的地方。

2. AQS加鎖原理

先分析一下,我們使用AQS的加鎖需求:

  • 多個線程執(zhí)行到ReentrantLock.lock方法的時候,只有一個線程獲取鎖,然后執(zhí)行同步代碼塊(需要記錄哪個線程獲取了對象鎖)。
  • 其他線程被阻塞(被阻塞的線程,是不是可以用鏈表設(shè)計個阻塞隊列?名叫”同步隊列“?)
  • 持有鎖的線程調(diào)用await方法,釋放鎖,等待被喚醒(等待的線程,是不是可以用鏈表設(shè)計個等待隊列?名叫”條件隊列“?)。
  • 被阻塞的線程開始競爭鎖
  • 調(diào)用signal方法,喚醒等待的線程,被喚醒的線程進入阻塞隊列,一塊競爭鎖。

AQS的需求跟Synchronized一模一樣。

我們再看一下AQS實際的加鎖機制是怎么設(shè)計的?是不是跟Synchronized相似?

AQS的加鎖流程并不復(fù)雜,只要理解了同步隊列條件隊列,以及它們之間的數(shù)據(jù)流轉(zhuǎn),就算徹底理解了AQS

  • 當(dāng)多個線程競爭AQS鎖時,如果有個線程獲取到鎖,就把ower線程設(shè)置為自己
  • 沒有競爭到鎖的線程,在同步隊列中阻塞(同步隊列采用雙向連接,尾插法)。
  • 持有鎖的線程調(diào)用await方法,釋放鎖,追加到條件隊列的末尾(條件隊列采用單鏈條,尾插法)。
  • 持有鎖的線程調(diào)用signal方法,喚醒條件隊列的頭節(jié)點,并轉(zhuǎn)移到同步隊列的末尾。
  • 同步隊列的頭節(jié)點優(yōu)先獲取到鎖

可以看到AQSSynchronized的加鎖流程幾乎是一模一樣的,AQS中同步隊列就是SynchronizedEntryListAQS中條件隊列就是Synchronized中的waitSet,兩個隊列之間的數(shù)據(jù)轉(zhuǎn)移流程也是一樣的。

3. 總結(jié)

AQSSynchronized的加鎖流程是一樣的,都是通過同步隊列和條件隊列實現(xiàn)的,阻塞狀態(tài)的線程被放到同步隊列中,等待狀態(tài)的線程被放到條件隊列中,從條件隊列喚醒的線程又被轉(zhuǎn)移到同步隊列末尾,一塊競爭鎖。

看完AQS加鎖流程,還沒有人不懂AQS的?

下篇文章再講一下AQS加鎖具體的源碼實現(xiàn)。里面有很多精巧的設(shè)計,值得我們學(xué)習(xí)。

比如:

為什么同步隊列要設(shè)計成雙向鏈表?而條件隊列要設(shè)計成單鏈表?

為什么AQS加鎖性能這么好(樂觀鎖CAS使用)?

同步隊列和條件隊列中節(jié)點怎么用一個對象實現(xiàn)?

釋放鎖后,怎么喚醒同步隊列中線程?

以上就是AQS加鎖機制Synchronized相似點詳解的詳細內(nèi)容,更多關(guān)于AQS加鎖機制Synchronized的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • Springboot死信隊列?DLX?配置和使用思路分析

    Springboot死信隊列?DLX?配置和使用思路分析

    死信隊列簡稱就是DLX,死信交換機和死信隊列和普通的沒有區(qū)別,當(dāng)消息成為死信后,如果該隊列綁定了死信交換機,則消息會被死信交換機重新路由到死信隊列,本文給大家介紹Springboot死信隊列?DLX的相關(guān)知識,感興趣的朋友一起看看吧
    2022-03-03
  • 詳解JAVA的封裝

    詳解JAVA的封裝

    Java面向?qū)ο蟮娜筇匦裕悍庋b、繼承、多態(tài)。下面對三大特性之一封裝進行了總結(jié),需要的朋友可以參考下
    2017-04-04
  • SpringBoot CommandLineRunner的異步任務(wù)機制使用

    SpringBoot CommandLineRunner的異步任務(wù)機制使用

    這篇文章主要介紹了SpringBoot CommandLineRunner的異步任務(wù)機制使用,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2024-08-08
  • java?Executors常用線程池

    java?Executors常用線程池

    這篇文章主要為大家介紹了java?Executors中提供的幾種常用的線程池使用示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2023-08-08
  • Mybatis查不到數(shù)據(jù)查詢返回Null問題

    Mybatis查不到數(shù)據(jù)查詢返回Null問題

    mybatis突然查不到數(shù)據(jù),查詢返回的都是Null,但是 select count(*) from xxx查詢數(shù)量,返回卻是正常的。好多朋友遇到這樣的問題不知所措,下面小編通過本教程簡單給大家說明下
    2016-08-08
  • java 虛擬機深入了解

    java 虛擬機深入了解

    這篇文章主要介紹了java 虛擬機深入了解的相關(guān)資料,ava虛擬機有自己完善的硬體架構(gòu),如處理器、堆棧、寄存器等,還具有相應(yīng)的指令系統(tǒng),需要的朋友可以參考下
    2017-03-03
  • Java實現(xiàn)單向鏈表反轉(zhuǎn)

    Java實現(xiàn)單向鏈表反轉(zhuǎn)

    這篇文章主要為大家詳細介紹了Java實現(xiàn)單向鏈表反轉(zhuǎn),文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2018-03-03
  • java基于移位操作實現(xiàn)二進制處理的方法示例

    java基于移位操作實現(xiàn)二進制處理的方法示例

    這篇文章主要介紹了java基于移位操作實現(xiàn)二進制處理的方法,結(jié)合實例形式分析了java針對二進制的移位操作處理技巧,需要的朋友可以參考下
    2017-02-02
  • spring-boot.version2.6升級到2.7.18后security報錯問題

    spring-boot.version2.6升級到2.7.18后security報錯問題

    這篇文章主要介紹了spring-boot.version2.6升級到2.7.18后security報錯問題及解決,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2024-08-08
  • Spring Boot 2.0 配置屬性自定義轉(zhuǎn)換的方法

    Spring Boot 2.0 配置屬性自定義轉(zhuǎn)換的方法

    這篇文章主要介紹了Spring Boot 2.0 配置屬性自定義轉(zhuǎn)換的方法,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2018-11-11

最新評論

苍梧县| 眉山市| 洛浦县| 泸溪县| 遵化市| 娄烦县| 墨玉县| 大石桥市| 吴江市| 天柱县| 石城县| 巴彦淖尔市| 嘉义市| 扶绥县| 南城县| 友谊县| 安陆市| 朝阳县| 吴旗县| 沐川县| 济阳县| 涟水县| 喀什市| 德安县| 通渭县| 尉氏县| 郁南县| 余江县| 永寿县| 新沂市| 恩平市| 阿拉善盟| 陇西县| 岱山县| 定结县| 自治县| 平湖市| 嘉祥县| 汉源县| 武陟县| 丰原市|