深入解析AbstractQueuedSynchronizer源碼3-共享模式

前面分析了AbstractQueuedSynchronizer實(shí)現(xiàn)的其他兩部分:
Condition源碼解析
獨(dú)占模式解析
本文繼續(xù)介紹AbstractQueuedSynchronizer最后一部分功能--共享模式

共享模式資源獲取

共享模式獲取資源的入口如下

// 忽略中斷異常
   public final void acquireShared(int arg) {
       if (tryAcquireShared(arg) < 0)
           doAcquireShared(arg);
   }
  // 拋出中斷異常
   public final void acquireSharedInterruptibly(int arg)
           throws InterruptedException {
       if (Thread.interrupted())
           throw new InterruptedException();
       if (tryAcquireShared(arg) < 0)
           doAcquireSharedInterruptibly(arg);
   }
   // 超時(shí)獲取,并拋出中斷異常
   public final boolean tryAcquireSharedNanos(int arg, long nanosTimeout)
           throws InterruptedException {
       if (Thread.interrupted())
           throw new InterruptedException();
       return tryAcquireShared(arg) >= 0 ||
           doAcquireSharedNanos(arg, nanosTimeout);
   }

tryAcquireShared留給工具自己去實(shí)現(xiàn)睬辐,用于判斷是否滿足獲取資源要求儡率,與獨(dú)占模式判斷函數(shù)不一樣,tryAcquire返回的是boolean食寡,因?yàn)槭仟?dú)占模式熄捍,每次只能一個(gè)線程獲取資源烛恤,所以直接返回boolean,共享模式下資源可以被多個(gè)線程通知占用余耽,tryAcquireShared返回int類型缚柏,表示還有多少個(gè)資源可以同時(shí)被占用,用于共享模式下傳播喚醒碟贾。

doAcquireShared

重點(diǎn)分析下doAcquireShared方法币喧,doAcquireSharedInterruptibly和doAcquireSharedNanos區(qū)別不是很大,不做分析

    private void doAcquireShared(int arg) {
        //添加共享模式節(jié)點(diǎn)袱耽,主要區(qū)分獨(dú)占模式
        final Node node = addWaiter(Node.SHARED);
        boolean failed = true;
        try {
            boolean interrupted = false;
            for (;;) {
                //拿到當(dāng)前節(jié)點(diǎn)的前驅(qū)節(jié)點(diǎn)杀餐,如果前驅(qū)節(jié)點(diǎn)是head節(jié)點(diǎn),說明沒有等待節(jié)點(diǎn)
                final Node p = node.predecessor();
                if (p == head) {
                    // 嘗試獲取資源扛邑,大于等于0怜浅,說明有資源獲取。
                    int r = tryAcquireShared(arg);
                    if (r >= 0) {
                        //把當(dāng)前節(jié)點(diǎn)設(shè)置成head節(jié)點(diǎn)蔬崩,并傳播喚醒后面的節(jié)點(diǎn)恶座。
                        setHeadAndPropagate(node, r);
                        p.next = null; // help GC
                        if (interrupted)
                            selfInterrupt();
                        failed = false;
                        return;
                    }
                }
                // 這里和獨(dú)占模式一樣,如果沒資源申請(qǐng)沥阳,封裝節(jié)點(diǎn)跨琳,并park等待
                if (shouldParkAfterFailedAcquire(p, node) &&
                        parkAndCheckInterrupt())
                    interrupted = true;
            }
        } finally {
            if (failed)
                cancelAcquire(node);
        }
    }

setHeadAndPropagate

    private void setHeadAndPropagate(Node node, int propagate) {
        // 設(shè)置head節(jié)點(diǎn),保留之前的head的節(jié)點(diǎn)桐罕,用于是否傳播喚醒之后節(jié)點(diǎn)判斷
        Node h = head; // Record old head for check below
        setHead(node);

        /**
         * 需要傳播喚醒的幾個(gè)條件
         * 1脉让,propagate>0,當(dāng)大于0的時(shí)候,說明還有其他資源空余功炮,需要傳播喚醒之后的節(jié)點(diǎn)
         * 2溅潜,head == null || head.waitStatus < 0,頭結(jié)點(diǎn)為空薪伏,
            head.waitStatus < 0即需要喚醒狀態(tài)或者是傳播狀態(tài)滚澜,也無條件嘗試喚醒之后的節(jié)點(diǎn)
         * 喚醒之后的節(jié)點(diǎn),會(huì)去重新嘗試獲取資源嫁怀。
         * 這里存在誤喚醒设捐,不過沒關(guān)系,喚醒之后的節(jié)點(diǎn)塘淑,會(huì)繼續(xù)回到doAcquireShared for循環(huán)中萝招,嘗試獲取資源。
         */
        if (propagate > 0 || h == null || h.waitStatus < 0 ||
                (h = head) == null || h.waitStatus < 0) {
            Node s = node.next;
            // 判斷是否是共享節(jié)點(diǎn)
            if (s == null || s.isShared())
                doReleaseShared();
        }
    }

以上是共享模式獲取資源流程存捺,釋放資源函數(shù)如下:

doReleaseShared

    private void doReleaseShared() {
        for (;;) {
            Node h = head;
            if (h != null && h != tail) {
                int ws = h.waitStatus;
                // 如果head節(jié)點(diǎn)的后繼節(jié)點(diǎn)需要被喚醒槐沼,然后喚醒
                if (ws == Node.SIGNAL) {
                    if (!compareAndSetWaitStatus(h, Node.SIGNAL, 0))
                        continue;            // loop to recheck cases
                    unparkSuccessor(h);
                }
                // 如果head節(jié)點(diǎn)后沒有需要被喚醒的節(jié)點(diǎn),設(shè)置成PROPAGATE狀態(tài),然后傳播喚醒
                else if (ws == 0 &&
                        !compareAndSetWaitStatus(h, 0, Node.PROPAGATE))
                    continue;                // loop on failed CAS
            }
            if (h == head)                   // loop if head changed
                break;
        }
    }
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末母赵,一起剝皮案震驚了整個(gè)濱河市逸爵,隨后出現(xiàn)的幾起案子具滴,更是在濱河造成了極大的恐慌凹嘲,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,743評(píng)論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件构韵,死亡現(xiàn)場(chǎng)離奇詭異周蹭,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)疲恢,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,296評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門凶朗,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人显拳,你說我怎么就攤上這事棚愤。” “怎么了杂数?”我有些...
    開封第一講書人閱讀 157,285評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵宛畦,是天一觀的道長。 經(jīng)常有香客問我揍移,道長次和,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,485評(píng)論 1 283
  • 正文 為了忘掉前任那伐,我火速辦了婚禮踏施,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘罕邀。我一直安慰自己畅形,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,581評(píng)論 6 386
  • 文/花漫 我一把揭開白布诉探。 她就那樣靜靜地躺著日熬,像睡著了一般。 火紅的嫁衣襯著肌膚如雪阵具。 梳的紋絲不亂的頭發(fā)上碍遍,一...
    開封第一講書人閱讀 49,821評(píng)論 1 290
  • 那天,我揣著相機(jī)與錄音阳液,去河邊找鬼怕敬。 笑死,一個(gè)胖子當(dāng)著我的面吹牛帘皿,可吹牛的內(nèi)容都是我干的东跪。 我是一名探鬼主播,決...
    沈念sama閱讀 38,960評(píng)論 3 408
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼虽填!你這毒婦竟也來了丁恭?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,719評(píng)論 0 266
  • 序言:老撾萬榮一對(duì)情侶失蹤斋日,失蹤者是張志新(化名)和其女友劉穎牲览,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體恶守,經(jīng)...
    沈念sama閱讀 44,186評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡第献,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,516評(píng)論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了兔港。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片庸毫。...
    茶點(diǎn)故事閱讀 38,650評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖衫樊,靈堂內(nèi)的尸體忽然破棺而出飒赃,到底是詐尸還是另有隱情,我是刑警寧澤科侈,帶...
    沈念sama閱讀 34,329評(píng)論 4 330
  • 正文 年R本政府宣布载佳,位于F島的核電站,受9級(jí)特大地震影響兑徘,放射性物質(zhì)發(fā)生泄漏刚盈。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,936評(píng)論 3 313
  • 文/蒙蒙 一挂脑、第九天 我趴在偏房一處隱蔽的房頂上張望藕漱。 院中可真熱鬧,春花似錦崭闲、人聲如沸肋联。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,757評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽橄仍。三九已至,卻和暖如春牍戚,著一層夾襖步出監(jiān)牢的瞬間侮繁,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,991評(píng)論 1 266
  • 我被黑心中介騙來泰國打工如孝, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留宪哩,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 46,370評(píng)論 2 360
  • 正文 我出身青樓第晰,卻偏偏與公主長得像锁孟,于是被迫代替她去往敵國和親彬祖。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,527評(píng)論 2 349

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