ReentrantReadWriteLock最最最經典示例用法----升級緩存後的鎖降級

所謂讀寫鎖,是對訪問資源共享鎖和排斥鎖,一般的重入性語義爲 如果對資源加了寫鎖,其他線程無法再獲得寫鎖與讀鎖,但是持有寫鎖的線程,可以對資源加讀鎖(鎖降級);如果一個線程對資源加了讀鎖,其他線程可以繼續加讀鎖。

下面的代碼展示瞭如何利用重入來執行升級緩存後的鎖降級(爲簡單起見,省略了異常處理及部分代碼):

class CachedData {
   Object data;
     //保證狀態可見性
   volatile boolean cacheValid;
   ReentrantReadWriteLock rwl = new ReentrantReadWriteLock();

   void processCachedData() {
     rwl.readLock().lock();
     if (!cacheValid) {
        // 在獲取寫鎖前必須釋放讀鎖
        rwl.readLock().unlock();
        rwl.writeLock().lock();
        //再次檢查其他線程是否已經搶到  
        if (!cacheValid) {
           //獲取數據
          data = ...
          cacheValid = true;
        }
        // 在釋放寫鎖之前通過獲取讀鎖來降級
        rwl.readLock().lock();
        //釋放寫鎖,保持讀鎖
        rwl.writeLock().unlock();
     }

     use(data);
     rwl.readLock().unlock();
   }
 }

ReentrantReadWriteLock並沒有繼承ReentrantLock,也並沒有實現Lock接口,而是實現了ReadWriteLock接口,該接口提供readLock()方法獲取讀鎖,writeLock()獲取寫鎖。

在使用某些種類的 Collection 時,可以使用 ReentrantReadWriteLock 來提高併發性。通常,在預期 collection 很大,讀取者線程訪問它的次數多於寫入者線程,並且 entail 操作的開銷高於同步開銷時,這很值得一試。例如,以下是一個使用 TreeMap 的類,預期它很大,並且能被同時訪問。

class RWDictionary {
    private final Map<String, Data> m = new TreeMap<String, Data>();
    private final ReentrantReadWriteLock rwl = new ReentrantReadWriteLock();
    private final Lock r = rwl.readLock();
    private final Lock w = rwl.writeLock();

    public Data get(String key) {
        r.lock();
        try { return m.get(key); }
        finally { r.unlock(); }
    }
    public String[] allKeys() {
        r.lock();
        try { return m.keySet().toArray(); }
        finally { r.unlock(); }
    }
    public Data put(String key, Data value) {
        w.lock();
        try { return m.put(key, value); }
        finally { w.unlock(); }
    }
    public void clear() {
        w.lock();
        try { m.clear(); }
        finally { w.unlock(); }
    }
 }
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章