Java concurrent包源碼走讀(三)

Java concurrent包源碼走讀(二)我們知道AQS中有個(gè)條件隊(duì)列,但是具體它的作用是干什么愕撰、它和同步隊(duì)列有個(gè)關(guān)系搞挣,接下來(lái)這篇我們來(lái)了解AQS中的條件隊(duì)列。首先我們先看一下和條件隊(duì)列關(guān)聯(lián)的ReentrantLock類叽躯。

ReentrantLock

類圖

從類圖中我們可以看到此類實(shí)現(xiàn)Lock,同時(shí)有個(gè)抽象類Sync馋嗜,Sync這個(gè)類是繼承AbstractQueuedSynchronizer齐板,同時(shí)它也兩個(gè)子類,F(xiàn)airSync和NonfairSync葛菇。由此可見ReentrantLock它可以公平的獲取鎖也可以非公平方式獲取鎖甘磨。我們通過(guò)源碼還可以看出ReentrantLock特點(diǎn):

  1. 互斥鎖

  2. 支持公平和非公平獲取鎖,默認(rèn)是非公平

  3. 可重入鎖

  4. 支持條件變量(實(shí)現(xiàn)Lock接口)

對(duì)于ReentrantLock獲取釋放鎖的源碼我們就再分析眯停,感興趣的同學(xué)可以走讀济舆,主要看tryAcquire和tryRelease方法。走讀的時(shí)候可以帶著下面的兩個(gè)問(wèn)題莺债?

  1. ReentrantLock如何實(shí)現(xiàn)可重入滋觉?

  2. ReentrantLock的Lock為何要需要try catch,并且lock需要在try的外面齐邦?

條件隊(duì)列

我們主通過(guò)await和signal方法分析同步隊(duì)列和條件隊(duì)列的交互椎侠。

await()方法
public final void await() throws InterruptedException {
    if (Thread.interrupted())
        throw new InterruptedException();
    //將節(jié)點(diǎn)放入等待隊(duì)列
    Node node = addConditionWaiter();
    //釋放節(jié)點(diǎn)占的鎖
    int savedState = fullyRelease(node);
    int interruptMode = 0;
    //輪詢判斷節(jié)點(diǎn)是否在AQS隊(duì)列
    while (!isOnSyncQueue(node)) {
        //如果在則阻塞節(jié)點(diǎn)對(duì)應(yīng)的線程
        //它是何時(shí)加入到AQS隊(duì)列中呢?signal()
        LockSupport.park(this);
        if ((interruptMode = checkInterruptWhileWaiting(node)) != 0)
            break;
    }
    //喚醒后繼續(xù)競(jìng)爭(zhēng)鎖措拇,失敗后繼續(xù)阻塞
    if (acquireQueued(node, savedState) && interruptMode != THROW_IE)
        interruptMode = REINTERRUPT;
    if (node.nextWaiter != null) // clean up if cancelled
        unlinkCancelledWaiters();
    if (interruptMode != 0)
        reportInterruptAfterWait(interruptMode);
}

signal()方法
public final void signal() {
        if (!isHeldExclusively())
            throw new IllegalMonitorStateException();
        Node first = firstWaiter;
        if (first != null)
            doSignal(first);
    }

private void doSignal(Node first) {
    do {
        if ( (firstWaiter = first.nextWaiter) == null)
            lastWaiter = null;
        first.nextWaiter = null;
    //喚醒等待隊(duì)列第一個(gè)節(jié)點(diǎn)我纪,注意只是喚醒,競(jìng)爭(zhēng)到鎖的看AQS隊(duì)列
    } while (!transferForSignal(first) &&
             (first = firstWaiter) != null);
}

通過(guò)上面源碼的分析丐吓,我們知道AQS自己維護(hù)的隊(duì)列是當(dāng)前等待資源的隊(duì)列浅悉,AQS會(huì)在資源被釋放后,依次喚醒隊(duì)列中從前到后的所有節(jié)點(diǎn)汰蜘,使他們對(duì)應(yīng)的線程恢復(fù)執(zhí)行仇冯。直到隊(duì)列為空。而條件隊(duì)列維護(hù)一個(gè)等待signal信號(hào)的隊(duì)列族操,兩個(gè)隊(duì)列的作用是不同苛坚,事實(shí)上比被,每個(gè)線程也僅僅會(huì)同時(shí)存在以上兩個(gè)隊(duì)列中的一個(gè)泼舱,流程是這樣的:

  1. 線程1調(diào)用reentrantLock.lock時(shí)等缀,線程被加入到AQS的等待隊(duì)列中娇昙。

  2. 線程1調(diào)用await方法被調(diào)用時(shí)尺迂,該線程從AQS中移除冒掌,對(duì)應(yīng)操作是鎖的釋放噪裕。

  3. 接著馬上被加入到Condition的等待隊(duì)列中,意味著該線程需要signal信號(hào)股毫。

  4. 線程2因?yàn)榫€程1釋放鎖的關(guān)系,被喚醒铃诬,并判斷可以獲取鎖,于是線程2獲取鎖趣席,并被加入到AQS的等待隊(duì)列中兵志。

  5. 線程2調(diào)用signal方法,這個(gè)時(shí)候Condition的等待隊(duì)列中只有線程1一個(gè)節(jié)點(diǎn)宣肚,于是它被取出來(lái)想罕,并被加入到AQS的等待隊(duì)列中。注意弧呐,這個(gè)時(shí)候線程1并沒有被喚醒

  6. signal方法執(zhí)行完畢,線程2調(diào)用reentrantLock.unLock()方法俘枫,釋放鎖。這個(gè)時(shí)候因?yàn)锳QS中只有線程1鸠蚪,于是师溅,AQS釋放鎖后按從頭到尾的順序喚醒線程時(shí)茅信,線程1被喚醒墓臭,于是線程1回復(fù)執(zhí)行蘸鲸。

  7. 直到釋放所整個(gè)過(guò)程執(zhí)行完畢窿锉。

可以看到膝舅,整個(gè)協(xié)作過(guò)程是靠結(jié)點(diǎn)在AQS的等待隊(duì)列和條件隊(duì)列中來(lái)回移動(dòng)實(shí)現(xiàn)的窑多,條件隊(duì)列維護(hù)了一個(gè)等待信號(hào)的節(jié)點(diǎn)仍稀,并在適時(shí)的時(shí)候?qū)⒔Y(jié)點(diǎn)加入到AQS的等待隊(duì)列中來(lái)實(shí)現(xiàn)的喚醒操作埂息。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市千康,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌琉闪,老刑警劉巖,帶你破解...
    沈念sama閱讀 222,729評(píng)論 6 517
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異斯入,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)刻两,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,226評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)滋迈,“玉大人户誓,你說(shuō)我怎么就攤上這事饼灿〉勖溃” “怎么了?”我有些...
    開封第一講書人閱讀 169,461評(píng)論 0 362
  • 文/不壞的土叔 我叫張陵悼潭,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我舰褪,道長(zhǎng)皆疹,這世上最難降的妖魔是什么占拍? 我笑而不...
    開封第一講書人閱讀 60,135評(píng)論 1 300
  • 正文 為了忘掉前任捎迫,我火速辦了婚禮残制,結(jié)果婚禮上立砸,老公的妹妹穿的比我還像新娘初茶。我一直安慰自己,他們只是感情好恼布,可當(dāng)我...
    茶點(diǎn)故事閱讀 69,130評(píng)論 6 398
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著折汞,像睡著了一般。 火紅的嫁衣襯著肌膚如雪爽待。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,736評(píng)論 1 312
  • 那天膏燃,我揣著相機(jī)與錄音,去河邊找鬼组哩。 笑死,一個(gè)胖子當(dāng)著我的面吹牛伶贰,可吹牛的內(nèi)容都是我干的罐栈。 我是一名探鬼主播黍衙,決...
    沈念sama閱讀 41,179評(píng)論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼荠诬,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了浅妆?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 40,124評(píng)論 0 277
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤辩尊,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后摄欲,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體轿亮,經(jīng)...
    沈念sama閱讀 46,657評(píng)論 1 320
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡胸墙,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,723評(píng)論 3 342
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了但骨。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,872評(píng)論 1 353
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡奔缠,死狀恐怖吼野,靈堂內(nèi)的尸體忽然破棺而出校哎,到底是詐尸還是另有隱情瞳步,我是刑警寧澤,帶...
    沈念sama閱讀 36,533評(píng)論 5 351
  • 正文 年R本政府宣布单起,位于F島的核電站,受9級(jí)特大地震影響馏臭,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜讼稚,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,213評(píng)論 3 336
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望锐想。 院中可真熱鬧,春花似錦赠摇、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,700評(píng)論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)洽故。三九已至,卻和暖如春时甚,著一層夾襖步出監(jiān)牢的瞬間哈踱,已是汗流浹背梨熙。 一陣腳步聲響...
    開封第一講書人閱讀 33,819評(píng)論 1 274
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留咽扇,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 49,304評(píng)論 3 379
  • 正文 我出身青樓肌割,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親把敞。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,876評(píng)論 2 361

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