AQS的基本原理

AQS(AbstractQueuedSynchronizer)是一個(gè)用于構(gòu)建鎖和同步器的框架汁政,許多同步器都可以通過AQS很容易并且高效的構(gòu)造出來。不僅Reentrant和Semaphore是基于AQS構(gòu)建的,還包括CountDownLatch寒瓦、ReentrantReadWriteLock、SynchronousQueue和FutureTask。

高層抽象

在基于AQS構(gòu)建的同步器類中诗良,最基本的操作包括各種形式的獲取操作和釋放操作。

獲取操作是一種依賴狀態(tài)的操作鲁驶,并且通常會(huì)阻塞直到達(dá)到了理想狀態(tài)鉴裹。如:

  • 使用ReentrantLock時(shí),“獲取”操作意味著“等待直到鎖可被獲取”。
  • 使用Semaphore時(shí)径荔,“獲取”操作意味著“等待直到許可可被獲取”督禽。
  • 使用CountDownLatch時(shí),“獲取”操作意味著“等待直到閉鎖達(dá)到結(jié)束狀態(tài)”总处。
  • 使用FutureTask時(shí)狈惫,“獲取”操作意味著“等待直到任務(wù)完成”。

釋放并不是一個(gè)可阻塞的操作鹦马,當(dāng)執(zhí)行“釋放”操作時(shí)胧谈,所有在請求時(shí)被阻塞的線程都會(huì)開始執(zhí)行。

內(nèi)部原理

狀態(tài)機(jī)

AQS提供了一個(gè)高效的狀態(tài)機(jī)模型荸频,用來管理同步器類中的狀態(tài)和菱肖。

狀態(tài)

AQS使用一個(gè)整數(shù)state以表示狀態(tài),并通過getState旭从、setState及compareAndSetState等protected類型方法進(jìn)行狀態(tài)轉(zhuǎn)換稳强。巧妙的使用state,可以表示任何狀態(tài)和悦,如:

  • ReentrantLock用state表示所有者線程已經(jīng)重復(fù)獲取該鎖的次數(shù)退疫。
  • Semaphore用state表示剩余的許可數(shù)量。
  • CountDownLatch用state表示閉鎖的狀態(tài)摹闽,如關(guān)閉蹄咖、打開。
  • FutureTask用state表示任務(wù)的狀態(tài)付鹿,如尚未開始澜汤、正在運(yùn)行、已完成舵匾、已取消俊抵。

除了state,在同步器類中還可以自行管理一些額外的狀態(tài)變量坐梯。如:

  • ReentrantLock保存了鎖的當(dāng)前所有者的信息徽诲,這樣就能區(qū)分某個(gè)獲取操作是重入的還是競爭的。
  • FutureTask用result表示任務(wù)的結(jié)果吵血,該結(jié)果可能是計(jì)算得到的答案谎替,也可能是拋出的異常。

狀態(tài)轉(zhuǎn)換

狀態(tài)轉(zhuǎn)換則表現(xiàn)為不同的獲取操作和釋放操作蹋辅,其標(biāo)準(zhǔn)形式如下:

boolean acquire () throws InterruptedException {
  while (當(dāng)前狀態(tài)不允許獲取操作) {
    if (需要阻塞獲取請求) {
      如果當(dāng)前線程不在隊(duì)列中钱贯,則將其插入隊(duì)列
      阻塞當(dāng)前新城
    }
    else
      返回失敗
  }
  可能更新同步器的狀態(tài)
  如果當(dāng)前線程在隊(duì)列中,則將其移出隊(duì)列
  返回成功
}

void release () {
  更新同步器的狀態(tài)
  if (新的狀態(tài)允許某個(gè)被阻塞的線程獲取成功)
    接觸隊(duì)列中一個(gè)或多個(gè)線程的阻塞狀態(tài)
}

為什么10行只是“可能”侦另,而不是“必然”更新同步器的狀態(tài)呢秩命?因?yàn)楂@取同步器的某個(gè)線程可能對其他線程能否也獲取該同步器造成影響尉共,也可能不影響。如使用獨(dú)占的ReentrantLock時(shí)弃锐,一個(gè)線程獲取鎖后袄友,其他線程就不能再獲取鎖,于是需要更新同步器的狀態(tài)霹菊;但使用CountDownLatch時(shí)剧蚣,一個(gè)線程獲取閉鎖時(shí)(包括正在獲取和獲取后),不會(huì)影響其他線程能否獲取它浇辜,因此不需要更新同步器的狀態(tài)券敌。

一些約定

根據(jù)是否支持阻塞、是否支持獨(dú)占等柳洋,獲取操作和釋放操作都有多個(gè)實(shí)現(xiàn)待诅。獲取操作有acquire、acquireShared熊镣、tryAcquire卑雁、tryAcquireShared等,釋放操作有release绪囱、releaseShared测蹲、tryRelease、tryReleaseShared等鬼吵。

還有acquireNanos扣甲、acquireInterruptibly等實(shí)現(xiàn),為了講解方便齿椅,暫時(shí)忽略它們琉挖。

不帶try前綴的方法是阻塞的(當(dāng)然release、releaseShared不是可阻塞的)涣脚,通過調(diào)用帶try前綴的相應(yīng)版本實(shí)現(xiàn)示辈,如acquire內(nèi)部調(diào)用tryAcquire并維護(hù)相關(guān)邏輯。AQS抽象類中提供了不帶try前綴的方法遣蚀,并以final修飾矾麻,在實(shí)現(xiàn)同步器時(shí)應(yīng)直接使用;需要覆寫的是帶try前綴的方法芭梯。對于這些方法险耀,約定通過返回值告知調(diào)用者(一般是AQS)獲取或釋放操作是否成功,一些特殊的值代表額外的信息

  • 對于tryAcquire玖喘,如果返回true胰耗,則表示獲取成功;否則返回false芒涡。
  • 對于tryAcquireShared柴灯,如果返回一個(gè)負(fù)值,那么表示獲取操作失敗费尽,返回零值表示同步器通過獨(dú)占方式被獲取赠群,返回正值表示同步器通過非獨(dú)占方式被獲取。
  • 對于tryRelease與tryReleaseShared方法來說旱幼,如果返回true查描,則表示已完全釋放,所有在獲取同步器時(shí)被阻塞的線程都可以被恢復(fù)執(zhí)行柏卤;否則返回false冬三。

要想基于AQS構(gòu)建同步器,就必須對上述四個(gè)方法爛熟于心缘缚。

總結(jié)

  • state表示狀態(tài)勾笆,其他狀態(tài)需要自行維護(hù)
  • 直接使用不帶try前綴的方法,并覆寫帶try前綴的方法
  • 對于帶try前綴的方法桥滨,約定通過返回值告知調(diào)用者(一般是AQS)獲取或釋放操作的結(jié)果

本文雖短窝爪,且非常重要,是后文分析ReentrantLock等的基礎(chǔ)齐媒。同時(shí)蒲每,又是一個(gè)高效并發(fā)的經(jīng)典設(shè)計(jì)案例。


本文鏈接:AQS的基本原理
作者:猴子007
出處:https://monkeysayhi.github.io
本文基于 知識(shí)共享署名-相同方式共享 4.0 國際許可協(xié)議發(fā)布喻括,歡迎轉(zhuǎn)載邀杏,演繹或用于商業(yè)目的,但是必須保留本文的署名及鏈接唬血。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末望蜡,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子刁品,更是在濱河造成了極大的恐慌泣特,老刑警劉巖,帶你破解...
    沈念sama閱讀 222,807評論 6 518
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件挑随,死亡現(xiàn)場離奇詭異状您,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)兜挨,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,284評論 3 399
  • 文/潘曉璐 我一進(jìn)店門膏孟,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人拌汇,你說我怎么就攤上這事柒桑。” “怎么了噪舀?”我有些...
    開封第一講書人閱讀 169,589評論 0 363
  • 文/不壞的土叔 我叫張陵魁淳,是天一觀的道長飘诗。 經(jīng)常有香客問我,道長界逛,這世上最難降的妖魔是什么昆稿? 我笑而不...
    開封第一講書人閱讀 60,188評論 1 300
  • 正文 為了忘掉前任,我火速辦了婚禮息拜,結(jié)果婚禮上溉潭,老公的妹妹穿的比我還像新娘。我一直安慰自己少欺,他們只是感情好喳瓣,可當(dāng)我...
    茶點(diǎn)故事閱讀 69,185評論 6 398
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著赞别,像睡著了一般畏陕。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上氯庆,一...
    開封第一講書人閱讀 52,785評論 1 314
  • 那天蹭秋,我揣著相機(jī)與錄音,去河邊找鬼堤撵。 笑死仁讨,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的实昨。 我是一名探鬼主播洞豁,決...
    沈念sama閱讀 41,220評論 3 423
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼荒给!你這毒婦竟也來了丈挟?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 40,167評論 0 277
  • 序言:老撾萬榮一對情侶失蹤志电,失蹤者是張志新(化名)和其女友劉穎曙咽,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體挑辆,經(jīng)...
    沈念sama閱讀 46,698評論 1 320
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡例朱,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,767評論 3 343
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了鱼蝉。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片洒嗤。...
    茶點(diǎn)故事閱讀 40,912評論 1 353
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖魁亦,靈堂內(nèi)的尸體忽然破棺而出渔隶,到底是詐尸還是另有隱情,我是刑警寧澤洁奈,帶...
    沈念sama閱讀 36,572評論 5 351
  • 正文 年R本政府宣布间唉,位于F島的核電站绞灼,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏呈野。R本人自食惡果不足惜镀赌,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,254評論 3 336
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望际跪。 院中可真熱鬧,春花似錦喉钢、人聲如沸姆打。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,746評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽幔戏。三九已至,卻和暖如春税课,著一層夾襖步出監(jiān)牢的瞬間闲延,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,859評論 1 274
  • 我被黑心中介騙來泰國打工韩玩, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留垒玲,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 49,359評論 3 379
  • 正文 我出身青樓找颓,卻偏偏與公主長得像合愈,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個(gè)殘疾皇子击狮,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,922評論 2 361

推薦閱讀更多精彩內(nèi)容