ReentrantReadWriteLock源碼解析

NonfairSync ReentrantReadWriteLock

static final class NonfairSync extends Sync {
    private static final long serialVersionUID = -8159625535654395037L;
    final boolean writerShouldBlock() {
        return false; //非公平實現,總是返回false 不會阻塞
    }
    final boolean readerShouldBlock() {
         //隊列的head後面的節點不爲空且爲非共享的就返回true 就阻塞
        return apparentlyFirstQueuedIsExclusive();
    }
}

FairSync ReentrantReadWriteLock

//查看隊列是否有先驅
static final class FairSync extends Sync {
    private static final long serialVersionUID = -2274990926593161451L;
    final boolean writerShouldBlock() {
        return hasQueuedPredecessors();
    }
    final boolean readerShouldBlock() {
        return hasQueuedPredecessors();
    }
}

ReentrantReadWriteLock的同步實現Sync

abstract static class Sync extends AbstractQueuedSynchronizer {
   private static final long serialVersionUID = 6317671515068378041L;

   /*使用一個32位的int類型來表示被佔用的線程數
    加鎖的區域被分爲兩部分,低16位代表獨佔鎖的被同一個線程申請的次數
    高位代表共享讀鎖佔有的線程數量*/
   static final int SHARED_SHIFT   = 16;//讀鎖佔用的位數
   static final int SHARED_UNIT    = (1 << SHARED_SHIFT);增加一個讀鎖相當於增加一個SHARED_UNIT
   static final int MAX_COUNT      = (1 << SHARED_SHIFT) - 1;//申請讀鎖的最大線程數量 65535
   static final int EXCLUSIVE_MASK = (1 << SHARED_SHIFT) - 1;//計算寫鎖的具體值時,該值爲15個1,

   //計算申請讀鎖的線程數,將c向右移位16就得到高16位的值  
   static int sharedCount(int c)    { return c >>> SHARED_SHIFT; }
   //計算申請寫鎖的數量,將c和16個1相與得到低16位
   static int exclusiveCount(int c) { return c & EXCLUSIVE_MASK; }

   //每個線程有多少讀鎖
   static final class HoldCounter {
       int count = 0;
       // 使用線程id來避免垃圾保留
       final long tid = getThreadId(Thread.currentThread());
   }

   /**
    * ThreadLocal subclass. Easiest to explicitly define for sake
    * of deserialization mechanics.
    */
   static final class ThreadLocalHoldCounter
       extends ThreadLocal<HoldCounter> {
       public HoldCounter initialValue() {
           return new HoldCounter();
       }
   }

   //當前線程的可重入讀鎖的數量,無論什麼時候一個線程的readHolds變成0就釋放鎖
   private transient ThreadLocalHoldCounter readHolds;

   private transient HoldCounter cachedHoldCounter;

    //第一個獲取讀鎖的線程
   private transient Thread firstReader = null;
   private transient int firstReaderHoldCount;

   Sync() {
       readHolds = new ThreadLocalHoldCounter();
       setState(getState()); // ensures visibility of readHolds
   }
   abstract boolean readerShouldBlock();
   abstract boolean writerShouldBlock();

   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;
   }

   protected final boolean tryAcquire(int acquires) {
       /*
        * Walkthrough:
        * 1.讀鎖的數量非0或者寫鎖的數量非0,並且鎖的擁有者是其他線程,獲取失敗
        * 2. 如果鎖的數量飽和大於65535,失敗
        * 3.
        */
       Thread current = Thread.currentThread();
       int c = getState();//
       int w = exclusiveCount(c);//申請寫鎖的數量
       if (c != 0) {
           // (Note: if c != 0 and w == 0 讀鎖數量不爲0,獨佔鎖獲取失敗)
           if (w == 0 || current != getExclusiveOwnerThread())//條件1
               return false;
           if (w + exclusiveCount(acquires) > MAX_COUNT)//條件2
               throw new Error("Maximum lock count exceeded");
           // 可重入
           setState(c + acquires);
           return true;
       }
       //c==0,說明當前沒有鎖
       if (writerShouldBlock() ||//這個實現在子類中,根據是否公平區分
           !compareAndSetState(c, c + acquires))
           return false;
       setExclusiveOwnerThread(current);
       return true;
   }
//體現firstReader和cachedHoldCounter作用,減少調用readHolds的get方法次數
   protected final boolean tryReleaseShared(int unused) {
       Thread current = Thread.currentThread();
       if (firstReader == current) {
           // assert firstReaderHoldCount > 0;
           if (firstReaderHoldCount == 1)
               firstReader = null;
           else
               firstReaderHoldCount--;
       } else {
           HoldCounter rh = cachedHoldCounter;
           //判斷當前線程是否是cachedHoldCounter,
           //不是就調用readHold的get方法獲取
           if (rh == null || rh.tid != getThreadId(current))
               rh = readHolds.get();//從ThreadLocalMap中獲取當前線程
           int count = rh.count;
           if (count <= 1) {
               readHolds.remove();//ThreadLocalMap中移除當前線程
               if (count <= 0)
                   throw unmatchedUnlockException();
           }
           --rh.count;//讀鎖數量減一
       }
       for (;;) {
           int c = getState();
           int nextc = c - SHARED_UNIT;
           if (compareAndSetState(c, nextc))
               // 釋放讀鎖並且不會影響到其他讀者
               //但是他可能允許等待的寫者運行,如果讀 寫鎖都是空閒的
               return nextc == 0;
       }
   }


   protected final int tryAcquireShared(int unused) {
       /*
        * 1. If write lock held by another thread, fail.如果寫鎖被其他線程佔有,失敗
        * 2. 
        */
       Thread current = Thread.currentThread();
       int c = getState();
       if (exclusiveCount(c) != 0 &&
           getExclusiveOwnerThread() != current)
           return -1;
       int r = sharedCount(c);
       if (!readerShouldBlock() &&
           r < MAX_COUNT &&
           compareAndSetState(c, c + SHARED_UNIT)) {
           if (r == 0) {
               firstReader = current;
               firstReaderHoldCount = 1;
           } else if (firstReader == current) {
               firstReaderHoldCount++;
           } else {
               HoldCounter rh = cachedHoldCounter;
               if (rh == null || rh.tid != getThreadId(current))
                   cachedHoldCounter = rh = readHolds.get();
               else if (rh.count == 0)
                   readHolds.set(rh);
               rh.count++;
           }
           return 1;
       }
       return fullTryAcquireShared(current);
   }
   /**
1.獲取當前是否已經被鎖住,如果c!=0 判斷寫鎖的申請數量是否爲0,是則轉2
不是就判斷是否是當前線程佔用寫鎖,不是返回false是則轉2
2.判斷寫鎖的數量是否超過最大值,是則拋出錯誤,不是就轉3
3.cas的設置c失敗則返回false,否則設置當前線程獨佔鎖,返回true
    */
   final boolean tryWriteLock() {
       Thread current = Thread.currentThread();
       int c = getState();
       if (c != 0) {
           int w = exclusiveCount(c);
           if (w == 0 || current != getExclusiveOwnerThread())
               return false;
           if (w == MAX_COUNT)
               throw new Error("Maximum lock count exceeded");
       }
       if (!compareAndSetState(c, c + 1))
           return false;
       setExclusiveOwnerThread(current);
       return true;
   }

   /**
    1.寫鎖有沒有被佔用,沒有被佔用轉2,被佔用判斷釋放是當前線程佔用
    如果是當前線程佔用,轉2,不是返回false
    2.判斷讀鎖的最大數量有沒有超過最大數量,有拋出錯誤,沒有就轉3
    3.cas設置state更新firstReader firstReaderHoldCount cachedHoldCounter readHolds
    */
   final boolean tryReadLock() {
       Thread current = Thread.currentThread();
       for (;;) {
           int c = getState();
           if (exclusiveCount(c) != 0 &&
               getExclusiveOwnerThread() != current)
               return false;
           int r = sharedCount(c);
           if (r == MAX_COUNT)
               throw new Error("Maximum lock count exceeded");
           if (compareAndSetState(c, c + SHARED_UNIT)) {
               if (r == 0) {
                   firstReader = current;
                   firstReaderHoldCount = 1;
               } else if (firstReader == current) {
                   firstReaderHoldCount++;
               } else {
                   HoldCounter rh = cachedHoldCounter;
                   if (rh == null || rh.tid != getThreadId(current))
                       cachedHoldCounter = rh = readHolds.get();
                   else if (rh.count == 0)
                       readHolds.set(rh);
                   rh.count++;
               }
               return true;
           }
       }
   }
   final int getCount() { return getState(); }
}

小結:


  • 讀鎖是可以多個線程重入的,寫鎖只能是單個線程重入
  • 一個擁有寫鎖的線程可以擁有讀鎖,寫鎖降級爲讀鎖
  • 同時佔有讀鎖和寫鎖的線程釋放了寫鎖就降爲讀鎖,此時寫操作是無法重入的
    如果寫鎖還未完全釋放是可以重入的
  • 公平模式下讀寫鎖的順序必須按照AQS的隊列順序進行,非公平模式下要看
    head的下一個節點是否是獨佔的

發佈了91 篇原創文章 · 獲贊 4 · 訪問量 2萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章