AQS(6):閉鎖和信號量

CountDownLatch

閉鎖可以使一個或多個線程等待一組事件的發生,內部的計數器記錄了事件的數量。兩個主要的方法就是await和countDown。

public void await() throws InterruptedException {
        sync.acquireSharedInterruptibly(1);
}
 public void countDown() {
        sync.releaseShared(1)
}

可以看到,這兩種均使用了AQS中的共享類型方法。因此在同步器中他也需要實現tryAcquiredShared方法和tryReleaseShared方法。在tryAcquiredShared實現中,如果state=0則表示成功返回1(要等待的事件全部發生),表示后續的acquire也會成功,否則返回-1表示acquire失敗。在tryReleaseShared方法中,獲取state并減1(發生了一個事件),如果減到0則release成功。

然后我們描述一下await的整個過程。首先我們假設CountDownLatch的初始值為n。一個線程調用了await方法,此時同步器調用acquireSharedInterruptibly(1)。在這個方法中,首先會在共享模式下try一下,根據上一段我們的描述,此時state=n顯然不為0,那么try失敗,調用doAcquireSharedInterruptibly。在這個方法里,與其他acquire方法基本類似,都會在同步隊列添加一個節點,然后判斷前驅是否為head以決定能否立即try一次。如果前驅為head,并且try成功了需要調用setHeadAndPropagate(顯然本次不會調用)。然后會把前驅設為SIGNAL并阻塞當前線程。

接下來是countDown過程,表示一個事件發生了。還是一樣的首先都會try一下,獲取state并減1,此時state=n-1.我們先假設state仍舊大于0即還有事件沒有發生,那么tryReleaseShared會返回false。這種情況下releaseShared會直接返回!

那么當state=1的時候又調用了一次releaseShared會發生什么呢。同樣的我們先try一下,這是經過CAS比較我們發現state=0了!然后我們就需要研究一下同步隊列了,如果隊列頭結點是SIGNAL,就表明它的后繼正等待被喚醒,然后我們就解鎖其后繼節點(只解鎖了一個!)。這時,第一個進入同步隊列的線程被喚醒,它將從被阻塞的地方繼續執行,然后調用一次tryAcquireShared,此時會成功,因為state=0了。然后該節點將自己設置為隊列頭(setHeadAndPropagate),并在該方法內調用了一次doReleaseShared,這將導致后續的節點被依次喚醒。

Semaphore

信號量中有兩種模式,即公平和非公平模式。它用于實現控制同時訪問某個資源的操作數量。唯一的區別就是在tryAcquire的時候,公平模式會先看一下所在同步隊列前面有沒有節點在等,如果有則標記自己本次try失敗。

Semaphore的acquire操作會調用acquireSharedInterruptibly方法。此時如果資源數夠,那么CAS設置state。如果資源不夠,就需要進入同步隊列等待了。其執行結構與CountDownLatch并無區別。但要注意的是這里的tryAcquire很好的反映了該方法的定義,如果返回值>0,表示后繼的acquire可能會成功;如果返回值=0,那么本次成功,后繼的acquire不成功;如果<0則失敗。當資源值小于等于0的時候線程就會被park方法阻塞掉。

同樣的release操作會將信號量state遞增,并解鎖一個后繼節點。被喚醒的線程會繼續嘗試tryAcquire,如果遞增后的信號量依舊小于0,那么繼續阻塞。如果大于0,那么try成功,該節點將自己設為頭結點并繼續調用doReleaseShared()方法解鎖后繼節點。

通過這兩種可以發現,利用同步器的工具類需要的就是根據自己的需求實現相關的acquire和release操作。在閉鎖中,acquire成功與否取決于事件數是否為0,而在信號量中則取決于資源數是否大于0.同樣,操作release,閉鎖需要將事件數-1,而信號量需要將事件數+1.這兩種同步工具類均使用了共享模式,因為可能允許多個線程同時獲取鎖。并且release導致的解鎖只會解鎖一個后繼節點,后續節點的解鎖操作將依靠前驅節點的傳播過程。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 230,825評論 6 546
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,814評論 3 429
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 178,980評論 0 384
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 64,064評論 1 319
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,779評論 6 414
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 56,109評論 1 330
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 44,099評論 3 450
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 43,287評論 0 291
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,799評論 1 338
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,515評論 3 361
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,750評論 1 375
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,221評論 5 365
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,933評論 3 351
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,327評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,667評論 1 296
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,492評論 3 400
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,703評論 2 380

推薦閱讀更多精彩內容