自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

重大發(fā)現(xiàn),AQS加鎖機(jī)制竟然跟Synchronized有驚人的相似

開(kāi)發(fā) 前端
AQS跟Synchronized的加鎖流程是一樣的,都是通過(guò)同步隊(duì)列和條件隊(duì)列實(shí)現(xiàn)的,阻塞狀態(tài)的線(xiàn)程被放到同步隊(duì)列中,等待狀態(tài)的線(xiàn)程被放到條件隊(duì)列中,從條件隊(duì)列喚醒的線(xiàn)程又被轉(zhuǎn)移到同步隊(duì)列末尾,一塊競(jìng)爭(zhēng)鎖。

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

AQS全稱(chēng)**AbstractQueuedSynchronizer**,即抽象隊(duì)列同步器,是一種用來(lái)構(gòu)建鎖和同步器的框架。

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

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

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

1. Synchronized加鎖流程

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

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

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

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

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

圖片

上圖展示了對(duì)象鎖的基本工作機(jī)制:

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

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

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

2. AQS加鎖原理

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

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

AQS的需求跟Synchronized一模一樣。

我們?cè)倏匆幌翧QS實(shí)際的加鎖機(jī)制是怎么設(shè)計(jì)的?是不是跟Synchronized相似?

圖片

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

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

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

3. 總結(jié)

AQS跟Synchronized的加鎖流程是一樣的,都是通過(guò)同步隊(duì)列和條件隊(duì)列實(shí)現(xiàn)的,阻塞狀態(tài)的線(xiàn)程被放到同步隊(duì)列中,等待狀態(tài)的線(xiàn)程被放到條件隊(duì)列中,從條件隊(duì)列喚醒的線(xiàn)程又被轉(zhuǎn)移到同步隊(duì)列末尾,一塊競(jìng)爭(zhēng)鎖。

看完AQS加鎖流程,還沒(méi)有人不懂AQS的?

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

比如:

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

為什么AQS加鎖性能這么好(樂(lè)觀(guān)鎖CAS使用)?

同步隊(duì)列和條件隊(duì)列中節(jié)點(diǎn)怎么用一個(gè)對(duì)象實(shí)現(xiàn)?

釋放鎖后,怎么喚醒同步隊(duì)列中線(xiàn)程?

責(zé)任編輯:武曉燕 來(lái)源: 一燈架構(gòu)
相關(guān)推薦

2017-05-16 05:05:34

2019-05-09 19:00:40

量子加密加密技術(shù)安全

2021-12-08 08:30:55

Java AQS機(jī)制 Java 基礎(chǔ)

2019-12-16 10:27:10

機(jī)器學(xué)習(xí)人工智能AI

2021-08-02 07:57:03

SynchronizeJava語(yǔ)言

2021-08-24 10:25:19

thisclassJava

2024-06-05 19:11:23

2024-03-11 13:07:25

2023-11-06 14:55:33

2021-12-21 11:45:24

Log4Shell漏洞主機(jī)安全

2012-09-21 10:07:04

9月刊

2021-11-05 14:53:42

操作系統(tǒng)openEuler

2014-01-07 09:11:51

大數(shù)據(jù)云計(jì)算

2019-05-06 14:30:40

AI人工智能

2022-01-16 06:59:25

黑客網(wǎng)絡(luò)安全網(wǎng)絡(luò)攻擊

2017-11-02 15:44:11

內(nèi)存降價(jià)價(jià)格

2020-12-14 12:17:47

MySQL記錄語(yǔ)句

2020-03-18 13:21:06

F5 應(yīng)用服務(wù)報(bào)告

2025-03-26 00:55:00

點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)