StampedLock更好的讀寫鎖(gold_axe)

JDK8引入
主要是有樂觀讀, 就是完全無鎖, 讀到以后再去檢查下版本, 不行再說

好處

ReentrantReadWriteLock 的改進(jìn)就是加了樂觀讀, 這樣了避免了 ReentrantReadWriteLock 非公平鎖時(shí) 讀多寫少, 寫入隊(duì)以后一直輪不到,餓死的情況, 還提高了吞吐量

另外, 可以升級(jí) 也可以降級(jí)

壞處

ReentrantReadWriteLock 比, 功能少了, 只是一個(gè)子集

  • 不支持條件變量
  • 不能中斷線程
  • 不能重入

而且 ,本來是為內(nèi)部使用的, 用起來一定要按模板,比較復(fù)雜

樂觀讀

不能保證讀到是最新的, 可以拿到以后再驗(yàn)證, 完全無鎖, 性能好

使用 都是這個(gè)模板

   public String get(Integer key) {
        // 1. 嘗試通過樂觀讀模式讀取數(shù)據(jù),非阻塞
        long stamp = lock.tryOptimisticRead();
        // 2. 讀取數(shù)據(jù)到當(dāng)前線程棧
        String currentValue = idMap.get(key);
        // 3. 校驗(yàn)是否被其他線程修改過,true 表示未修改,否則需要加悲觀讀鎖
        if (!lock.validate(stamp)) {
            // 4. 上悲觀讀鎖,并重新讀取數(shù)據(jù)到當(dāng)前線程局部變量
            stamp = lock.readLock();
            try {
                currentValue = idMap.get(key);
            } finally {
                lock.unlockRead(stamp);
            }
        }
        // 5. 若校驗(yàn)通過,則直接返回?cái)?shù)據(jù)
        return currentValue;
    }

原理

ReentrantReadWriteLock 性能要高,內(nèi)部沒用AQS 但是 和AQS原理是一樣的 都是用的 CLH隊(duì)列


一樣是雙向鏈表, 有存了 頭尾 字段, 有個(gè)狀態(tài)state
也是狀態(tài)2 用, 又表示寫鎖又記讀鎖

注意有個(gè)NCPU字段, 記錄的是核數(shù), 如果核數(shù)>1 , 獲取鎖和入隊(duì) 都有自旋

CLH隊(duì)列的節(jié)點(diǎn)比AQS更加簡(jiǎn)單, 只有3種狀態(tài)


另外多了一個(gè) cowait字段, 記錄讀線程, 頭插法


這樣 如果前一個(gè)節(jié)點(diǎn)就是讀, 下一個(gè)讀就連入cowait了, 不像AQS往后連,
而且因?yàn)槭穷^插法, 晚來的讀 反而先叫起來, 不過反正不讀之間不阻塞, 差不多

得鎖 解鎖

獲取寫鎖:



cas試試, 失敗就入隊(duì),

入隊(duì)有大量自旋操作, 就是入前文所述的 CLH

讀鎖也差不多

釋放鎖:
ReentrantReadWriteLock 差不多 都改state, 叫醒隊(duì)列下一個(gè), 就是前面多了一步, 核對(duì)傳入的stamp, 如果對(duì)不上會(huì)拋出異常

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。