java源碼 - ReentrantReadWriteLock寫鎖介紹

開篇

?這篇文章主要從源碼角度講解ReentrantReadWriteLock的WriteLock的加鎖和減鎖過程号涯。
?ReentrantReadWriteLock的WriteLock加鎖解鎖過程依賴于AbstractQueuedSynchronizer(AQS)類,所以有些相同的邏輯可以看看ReentrantLock的邏輯五慈。


加鎖過程

  • WriteLock的lock()內(nèi)部通過sync.acquire(1)獲取鎖蝎土。
  • 嘗試通過tryAcquire獲取寫鎖慨代,如果獲取成功那么就成功占用寫鎖息罗。
  • 獲取寫鎖失敗后,將當(dāng)前線程添加到寫鎖喚醒隊(duì)列當(dāng)中acquireQueued(addWaiter(Node.EXCLUSIVE), arg))锥累。
  • acquireQueued(addWaiter(Node.EXCLUSIVE), arg))的操作邏輯和ReentrantLock的邏輯一致征懈。
    public static class WriteLock implements Lock, java.io.Serializable {
        private static final long serialVersionUID = -4992448646407690164L;
        private final Sync sync;

        protected WriteLock(ReentrantReadWriteLock lock) {
            sync = lock.sync;
        }

        public void lock() {
            sync.acquire(1);
        }
    }

    public final void acquire(int arg) {
        // 1、先嘗試獲取鎖tryAcquire
        // 2揩悄、獲鎖失敗就addWaiter操作
        // 3卖哎、acquireQueued判斷是否喚醒
        if (!tryAcquire(arg) &&
            acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
            selfInterrupt();
    }

tryAcquire過程

  • 獲取鎖狀態(tài)state變量,并獲取寫鎖占用的計(jì)數(shù)值删性。
  • 當(dāng)前state不為0亏娜,如果寫鎖狀態(tài)為0說明讀鎖被占用,返回鎖占用失敗蹬挺。
  • 鎖狀態(tài)state不為空且占鎖線程為當(dāng)前線程维贺,說明鎖被其他線程占用返回鎖占用失敗。
  • 寫鎖重入數(shù)溢出巴帮,返回鎖占用失敗溯泣。
  • 如果寫鎖阻塞 或者 設(shè)置state狀態(tài)失敗,返回鎖占用失敗榕茧。
  • 設(shè)置當(dāng)前鎖占用線程為當(dāng)前線程垃沦,返回鎖占用成功。
    protected final boolean tryAcquire(int acquires) {
            Thread current = Thread.currentThread();
            // 獲取鎖狀態(tài)state變量
            int c = getState();
            // 獲取寫鎖占用的計(jì)數(shù)
            int w = exclusiveCount(c);
            // 如果鎖狀態(tài)state不為0
            if (c != 0) {
                // 1用押、當(dāng)前state不為0肢簿,如果寫鎖狀態(tài)為0說明讀鎖此時被占用,說明鎖被讀鎖占用
                // 2蜻拨、鎖狀態(tài)state不為空且占鎖線程為當(dāng)前線程(屬于鎖重入)池充,說明鎖被其他線程占用
                if (w == 0 || current != getExclusiveOwnerThread())
                    return false;
                // 寫鎖重入數(shù)溢出
                if (w + exclusiveCount(acquires) > MAX_COUNT)
                    throw new Error("Maximum lock count exceeded");
                // 寫鎖獲取成功返回成功標(biāo)記
                setState(c + acquires);
                return true;
            }
            // 如果寫鎖阻塞 或者 設(shè)置state狀態(tài)失敗,那么就代表獲鎖失敗
            if (writerShouldBlock() ||
                !compareAndSetState(c, c + acquires))
                return false;
            // 設(shè)置當(dāng)前鎖占用線程為當(dāng)前線程
            setExclusiveOwnerThread(current);
            return true;
        }


解鎖過程

  • WriteLock的unlock()內(nèi)部通過sync. release(1)釋放鎖缎讼。
  • 嘗試通過tryRelease()方法來釋放鎖并喚醒下一個等待線程收夸。
  • 在喚醒過程中需要仔細(xì)看看讀寫鎖等待線程喚醒的細(xì)節(jié),待補(bǔ)充
    public void unlock() {
        sync.release(1);
    }

    public final boolean release(int arg) {
        if (tryRelease(arg)) {
            Node h = head;
            if (h != null && h.waitStatus != 0)
                unparkSuccessor(h);
            return true;
        }
        return false;
    }

tryRelease過程

  • 判斷當(dāng)前線程和鎖占用線程不一致isHeldExclusively()拋出異常血崭。
  • 鎖狀態(tài)減去當(dāng)前釋放動作傳入?yún)?shù)nextc = getState() - releases卧惜。
  • 判斷鎖狀態(tài)的寫狀態(tài)為0就表明當(dāng)前線程已經(jīng)完全釋放鎖。
  • 當(dāng)前線程完全釋放鎖功氨,然后設(shè)置鎖占用線程為null并設(shè)置鎖狀態(tài)序苏。
    protected final boolean tryRelease(int releases) {
        if (!isHeldExclusively())
            throw new IllegalMonitorStateException();
        int nextc = getState() - releases;
        boolean free = exclusiveCount(nextc) == 0;
        if (free)
            setExclusiveOwnerThread(null);
        setState(nextc);
        return free;
    }
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市捷凄,隨后出現(xiàn)的幾起案子忱详,更是在濱河造成了極大的恐慌,老刑警劉巖跺涤,帶你破解...
    沈念sama閱讀 217,826評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件匈睁,死亡現(xiàn)場離奇詭異监透,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)航唆,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,968評論 3 395
  • 文/潘曉璐 我一進(jìn)店門胀蛮,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人糯钙,你說我怎么就攤上這事粪狼。” “怎么了任岸?”我有些...
    開封第一講書人閱讀 164,234評論 0 354
  • 文/不壞的土叔 我叫張陵再榄,是天一觀的道長。 經(jīng)常有香客問我享潜,道長困鸥,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,562評論 1 293
  • 正文 為了忘掉前任剑按,我火速辦了婚禮疾就,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘艺蝴。我一直安慰自己猬腰,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,611評論 6 392
  • 文/花漫 我一把揭開白布吴趴。 她就那樣靜靜地躺著漆诽,像睡著了一般侮攀。 火紅的嫁衣襯著肌膚如雪锣枝。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,482評論 1 302
  • 那天兰英,我揣著相機(jī)與錄音撇叁,去河邊找鬼。 笑死畦贸,一個胖子當(dāng)著我的面吹牛陨闹,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播薄坏,決...
    沈念sama閱讀 40,271評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼趋厉,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了胶坠?” 一聲冷哼從身側(cè)響起君账,我...
    開封第一講書人閱讀 39,166評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎沈善,沒想到半個月后乡数,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體椭蹄,經(jīng)...
    沈念sama閱讀 45,608評論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,814評論 3 336
  • 正文 我和宋清朗相戀三年净赴,在試婚紗的時候發(fā)現(xiàn)自己被綠了绳矩。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,926評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡玖翅,死狀恐怖翼馆,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情金度,我是刑警寧澤写妥,帶...
    沈念sama閱讀 35,644評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站审姓,受9級特大地震影響珍特,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜魔吐,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,249評論 3 329
  • 文/蒙蒙 一扎筒、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧酬姆,春花似錦嗜桌、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,866評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至相满,卻和暖如春层亿,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背立美。 一陣腳步聲響...
    開封第一講書人閱讀 32,991評論 1 269
  • 我被黑心中介騙來泰國打工匿又, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人建蹄。 一個月前我還...
    沈念sama閱讀 48,063評論 3 370
  • 正文 我出身青樓碌更,卻偏偏與公主長得像,于是被迫代替她去往敵國和親洞慎。 傳聞我的和親對象是個殘疾皇子痛单,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,871評論 2 354