ReentrantReadWriteLock 可重入讀寫鎖的理解


  多線程讀取並修必一個資源時,我們過去通常使用synchronized同步鎖,這個是有性能損失的,很多情況下:資源對象總是被大量並發讀取,偶爾有一個線程進行修改,也就是說:以讀為主,修改不是很頻繁,那么我們在JDK5中用ReentrantReadWriteLock就獲得比synchronized更高並發性能,高並發性能是我們使用JDK5的主要目的,而不是annotaion和泛型等設計優點。

  在使用ReentrantReadWriteLock 時應明確以下幾點:

     (1)在代碼中添加讀鎖(lock.readLock().lock() ) 的目的:如果有一線程在讀取數據時,此時恰好有另一線程,正以寫鎖的方式在修改該數據,此時讀取數據的線程如果加了讀鎖,將被阻塞,直到另一線程的寫鎖被釋放才能繼續讀,而如果讀取數據的線程未加讀鎖,那么它的讀將不被阻塞,就有可能讀入被修改前的數據。總結:讀鎖離開了寫鎖就沒有了意義

  (2)重入:此鎖允許 reader 和 writer 按照 ReentrantLoc 的樣式重新獲取讀取鎖或寫入鎖。在寫入線程保持的所有寫入鎖都已經釋放后,才允許重入 reader 使用它們。此外,writer 可以獲取讀取鎖,但反過來則不成立。在其他應用程序中,當在調用或回調那些在讀取鎖狀態下執行讀取操作的方法期間保持寫入鎖時,重入很有用。如果 reader 試圖獲取寫入鎖,那么將永遠不會獲得成功。reentrant 鎖意味着什么呢?簡單來說,它有一個與鎖相關的獲取計數器,如果擁有鎖的某個線程再次得到鎖,那么獲取計數器就加1,然后鎖需要被釋放兩次才能獲得真正釋放。這模仿了 synchronized 的語義;如果線程進入由線程已經擁有的監控器保護的 synchronized 塊,就允許線程繼續進行,當線程退出第二個(或者后續) synchronized 塊的時候,不釋放鎖,只有線程退出它進入的監控器保護的第一個 synchronized 塊時,才釋放鎖。這相當於是模仿了synchronized中又可以嵌套一個synchronized這樣的場景

      (3)鎖降級:重入還允許從寫入鎖降級為讀取鎖,其實現方式是:先獲取寫入鎖,然后獲取讀取鎖,最后釋放寫入鎖。但是,從讀取鎖升級到寫入鎖是不可能的

下面是JDK的一個例子,展示了如何利用重入來執行升級緩存后的鎖降級(為簡單起見,省略了異常處理):

class CachedData {
   Object data;
   volatile boolean cacheValid;
   ReentrantReadWriteLock rwl = new ReentrantReadWriteLock();

   void processCachedData() {
     rwl.readLock().lock();
     if (!cacheValid) {
        // Must release read lock before acquiring write lock
        rwl.readLock().unlock();
        rwl.writeLock().lock();
        // Recheck state because another thread might have acquired
        //   write lock and changed state before we did.
        if (!cacheValid) {
          data = ...
          cacheValid = true;
        }
        // Downgrade by acquiring read lock before releasing write lock
        rwl.readLock().lock();
        rwl.writeLock().unlock(); // Unlock write, still hold read
     }

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

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM