jdk源碼解析七之ReadWriteLock

ReadWriteLock

在這裏插入圖片描述
分別維護2個鎖,寫鎖是獨佔鎖,讀鎖是共享鎖,因爲讀的時間通常比寫的時間長,所以寫鎖優先級比讀鎖高

ReentrantReadWriteLock

構造

     public ReentrantReadWriteLock() {
        //默認獨佔
        this(false);
    }

    public ReentrantReadWriteLock(boolean fair) {
        sync = fair ? new FairSync() : new NonfairSync();
        //靜態內部類
        readerLock = new ReadLock(this);
        ///靜態內部類
        writerLock = new WriteLock(this);
    }
     //高16讀鎖,低16寫鎖
        static final int SHARED_SHIFT   = 16;
        static final int SHARED_UNIT    = (1 << SHARED_SHIFT);
        static final int MAX_COUNT      = (1 << SHARED_SHIFT) - 1;
        static final int EXCLUSIVE_MASK = (1 << SHARED_SHIFT) - 1;

        /** Returns the number of shared holds represented in count  */
        //返回共享個數
        static int sharedCount(int c)    { return c >>> SHARED_SHIFT; }
        /** Returns the number of exclusive holds represented in count  */
        //返回獨佔個數
        static int exclusiveCount(int c) { return c & EXCLUSIVE_MASK; }

獲取讀寫鎖

    public ReentrantReadWriteLock.WriteLock writeLock() { return writerLock; }
    public ReentrantReadWriteLock.ReadLock  readLock()  { return readerLock; }

讀鎖

lock

     public void lock() {
            sync.acquireShared(1);
        }
        
 protected final int tryAcquireShared(int unused) {
            /*
             * Walkthrough:
             * 1. If write lock held by another thread, fail.
             * 2. Otherwise, this thread is eligible for
             *    lock wrt state, so ask if it should block
             *    because of queue policy. If not, try
             *    to grant by CASing state and updating count.
             *    Note that step does not check for reentrant
             *    acquires, which is postponed to full version
             *    to avoid having to check hold count in
             *    the more typical non-reentrant case.
             * 3. If step 2 fails either because thread
             *    apparently not eligible or CAS fails or count
             *    saturated, chain to version with full retry loop.
             */
            ///獲取當前線程
            Thread current = Thread.currentThread();
            //獲取當前鎖的數量
            int c = getState();
            //持有寫鎖失敗
            if (
                    //獲取獨佔鎖數量!=0
                    exclusiveCount(c) != 0 &&
                 //且當前擁有獨佔訪問權限的線程不等於當前線程,這裏寫鎖可降級
                getExclusiveOwnerThread() != current)
                return -1;
            //獲取共享鎖數量
            int r = sharedCount(c);
            /*
            第一次線程A讀取,則記錄第一個堵得線程以及個數
            第二次線程A讀取,則當前訪問線程個數+1
            第三次線程B讀取,利用cachedHoldCounter緩存當前線程tid以及訪問次數
            readHolds可以理解爲一級緩存,綁定了每個線程的線程計數器
            cachedHoldCounter:二級緩存,緩存上一個線程執行重入鎖的次數
             */
            if (//線程是否應該被阻塞
                    !readerShouldBlock() &&
                    //共享鎖數量<最大鎖數量
                r < MAX_COUNT &&
                    //更新共享鎖數量
                compareAndSetState(c, c + SHARED_UNIT)) {
                //如果是第一次讀取
                if (r == 0) {
                    //記錄第一個讀的線程
                    firstReader = current;
                    firstReaderHoldCount = 1;
                } else if (firstReader == current) {
                    //如果當前訪問的線程是第一個訪問的線程,則訪問線程數+1
                    firstReaderHoldCount++;
                } else {
                    //獲取計數器
                    HoldCounter rh = cachedHoldCounter;
                    //計數器爲null或者當前線程id不爲正在運行線程id
                    if (rh == null || rh.tid != getThreadId(current))
                        //獲取當前計數線程對應計數器
                        cachedHoldCounter = rh = readHolds.get();
                    else if (rh.count == 0)
                        //設置線程計數器
                        readHolds.set(rh);
                    //線程重入次數+1
                    rh.count++;
                }
                return 1;
            }
            //CAS尚未命中
            return fullTryAcquireShared(current);
        }
    final int fullTryAcquireShared(Thread current) {
            /*
             * This code is in part redundant with that in
             * tryAcquireShared but is simpler overall by not
             * complicating tryAcquireShared with interactions between
             * retries and lazily reading hold counts.
             */
            HoldCounter rh = null;
            for (;;) {
                int c = getState();
                //如果當前有獨佔鎖,且獨佔線程非當前線程,則返回
                if (exclusiveCount(c) != 0) {
                    if (getExclusiveOwnerThread() != current)
                        return -1;
                    // else we hold the exclusive lock; blocking here
                    // would cause deadlock.
                } else if (readerShouldBlock()) {
                    //寫鎖沒有被獲取,且讀線程被阻塞
                    // Make sure we're not acquiring read lock reentrantly
                    //當前第一個線程爲讀線程,說明當前線程重入
                    if (firstReader == current) {
                        // assert firstReaderHoldCount > 0;
                    } else {
                        if (rh == null) {
                            //獲取緩存的計數器
                            rh = cachedHoldCounter;
                            //沒有緩存計數器,或者計數器線程tid非當前線程tid(也就是說非上一個獲取鎖的線程)
                            //對寫鎖的讓步,如果第一個獲取鎖的線程是寫鎖,那麼後續所有線程AQS排隊
                            if (rh == null || rh.tid != getThreadId(current)) {
                                //獲取線程計數器
                                rh = readHolds.get();
                                //重入鎖數量爲0
                                if (rh.count == 0)
                                    //刪除計數器
                                    readHolds.remove();
                            }
                        }
                        //重入鎖數量爲0
                        if (rh.count == 0)
                            //AQS排隊
                            return -1;
                    }
                }
                //讀鎖數量超過上限,異常
                if (sharedCount(c) == MAX_COUNT)
                    throw new Error("Maximum lock count exceeded");
                //設置讀鎖數量

                //當前線程是第一個獲取讀鎖的線程,或是上一個執行任務的線程會執行到這裏
                //也就是說重入獲取讀鎖的線程纔會執行到這裏
                if (compareAndSetState(c, c + SHARED_UNIT)) {
                    //
                    if (sharedCount(c) == 0) {
                        firstReader = current;
                        firstReaderHoldCount = 1;
                    } else if (firstReader == current) {
                        firstReaderHoldCount++;
                    } else {
                        if (rh == null)
                            rh = cachedHoldCounter;
                        if (rh == null || rh.tid != getThreadId(current))
                            rh = readHolds.get();
                        else if (rh.count == 0)
                            readHolds.set(rh);
                        //重入數量累加
                        rh.count++;
                        //緩存計數器
                        cachedHoldCounter = rh; // cache for release
                    }
                    return 1;
                }
            }
        }

      final boolean readerShouldBlock() {
            //下一個鎖是否是獨佔鎖
            return apparentlyFirstQueuedIsExclusive();
        }
    final boolean apparentlyFirstQueuedIsExclusive() {
        Node h, s;
        return (h = head) != null &&
            (s = h.next)  != null &&
            !s.isShared()         &&
            s.thread != null;
    }

unlock

     protected final boolean tryReleaseShared(int unused) {
            //獲取當前線程
            Thread current = Thread.currentThread();
            //當前線程爲第一個獲取讀鎖的線程
            if (firstReader == current) {
                // assert firstReaderHoldCount > 0;
                //如果是最後一次釋放鎖,則直接置空firstReader
                if (firstReaderHoldCount == 1)
                    firstReader = null;
                else
                    //頭鎖重入次數-1
                    firstReaderHoldCount--;
            } else {
                //獲取上一個獲取讀鎖的線程計數器
                HoldCounter rh = cachedHoldCounter;
                if (rh == null || rh.tid != getThreadId(current))
                    //非上一次執行的線程,則獲取當前線程計數器
                    rh = readHolds.get();
                int count = rh.count;
                if (count <= 1) {
                    //刪除當前線程計數器
                    readHolds.remove();
                    //說明沒有之前獲取鎖,直接釋放則異常
                    if (count <= 0)
                        throw unmatchedUnlockException();
                }
                //線程重入次數-1
                --rh.count;
            }
            for (;;) {
                int c = getState();
                int nextc = c - SHARED_UNIT;
                if (compareAndSetState(c, nextc))
                    // Releasing the read lock has no effect on readers,
                    // but it may allow waiting writers to proceed if
                    // both read and write locks are now free.
                    //鎖爲0說明正確釋放
                    return nextc == 0;
            }
        }

寫鎖

lock

  protected final boolean tryAcquire(int acquires) {
  
            //獲取當前線程
            Thread current = Thread.currentThread();
            ///獲取當前線程狀態
            int c = getState();
            //獲取獨佔鎖重入數量
            int w = exclusiveCount(c);
            //如果有線程獲取讀寫鎖
            if (c != 0) {
                // (Note: if c != 0 and w == 0 then shared count != 0)
                //寫鎖沒被佔用,或當前擁有獨佔訪問權限的線程不等於當前線程,說明有讀鎖被佔用,返回false
                if (w == 0 || current != getExclusiveOwnerThread())
                    return false;
                //讀寫鎖數量超過最大數量,異常
                if (w + exclusiveCount(acquires) > MAX_COUNT)
                    throw new Error("Maximum lock count exceeded");
                // Reentrant acquire
                //執行到這裏,說明寫鎖被重入
                setState(c + acquires);
                return true;
            }
            //執行到這裏說明沒有讀寫鎖佔用
            if (
                    //寫鎖是否阻塞
                    writerShouldBlock() ||
                            //修改狀態
                !compareAndSetState(c, c + acquires))
                //如果寫鎖沒有被阻塞,且修改狀態失敗,則返回false
                return false;
            //設置鎖被當前線程獨佔
            setExclusiveOwnerThread(current);
            return true;
        }


非公平獲取鎖是否阻塞

    final boolean writerShouldBlock() {
            return false; // writers can always barge
        }

公平獲取鎖是否阻塞

    final boolean writerShouldBlock() {
            return hasQueuedPredecessors();
        }
   public final boolean hasQueuedPredecessors() {
        // The correctness of this depends on head being initialized
        // before tail and on head.next being accurate if the current
        // thread is first in queue.
        Node t = tail; // Read fields in reverse initialization order
        Node h = head;
        Node s;
        //判斷當前線程是否是等待線程節點的下一個線程
        return h != t &&
            ((s = h.next) == null || s.thread != Thread.currentThread());
    }

unlock


   protected final boolean tryRelease(int releases) {
            //擁有獨佔鎖的不是當前線程,則異常
            if (!isHeldExclusively())
                throw new IllegalMonitorStateException();
            int nextc = getState() - releases;
            boolean free = exclusiveCount(nextc) == 0;
            //獨佔鎖數量爲0,則清空鎖的持有者
            if (free)
                setExclusiveOwnerThread(null);
            //設置鎖數量
            setState(nextc);
            return free;
        }

鎖降級

在這裏插入圖片描述

 * class CachedData {
 *   Object data;
 *   volatile boolean cacheValid;
 *   final 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();
 *       try {
 *         // 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();
 *       } finally {
 *         rwl.writeLock().unlock(); // Unlock write, still hold read
 *       }
 *     }
 *
 *     try {
 *       use(data);
 *     } finally {
 *       rwl.readLock().unlock();
 *     }
 *   }
 * }}

總結

當獲取寫鎖的情況下,當前線程依舊能獲取讀鎖,這稱之爲鎖降級
當獲取讀鎖情況下,不能獲取寫鎖
這裏始終保證了寫鎖>讀鎖等級.
避免了鎖等級一樣,出現獲取鎖的亂序問題.

讀鎖添加的State是SHARED_UNIT的倍數

這裏分別用firstReader記錄第一個獲取讀鎖的線程
cachedHoldCounter獲取上一個獲取讀鎖的線程計數器
readHolds記錄每個線程鎖對應的計數器

如果下一個鎖是獨佔鎖,且非公平模式下,則後續所有線程都進入AQS等待鎖,只有已經獲取讀鎖的依舊可以執行

  final boolean readerShouldBlock() {
            //下一個鎖是否是獨佔鎖
            return apparentlyFirstQueuedIsExclusive();
        }
protected final int tryAcquireShared(int unused) {
     /////////////
            if (//線程是否應該被阻塞
                    !readerShouldBlock() &&{
           //...
            }
            //CAS尚未命中
            return fullTryAcquireShared(current);
        }

   final int fullTryAcquireShared(Thread current) {

            HoldCounter rh = null;
            for (;;) {
                int c = getState();
                //如果當前有獨佔鎖,且獨佔線程非當前線程,則返回
                if (exclusiveCount(c) != 0) {
                    if (getExclusiveOwnerThread() != current)
                        return -1;
                        /////////////////////////
                } else if (readerShouldBlock()) {
             /////////////////////////////////
                }

                //讀鎖數量超過上限,異常
                if (sharedCount(c) == MAX_COUNT)
                    throw new Error("Maximum lock count exceeded");
                //設置讀鎖數量

                //當前線程是第一個獲取讀鎖的線程,或是上一個執行任務的線程會執行到這裏
                //也就是說重入獲取讀鎖的線程纔會執行到這裏
                if (compareAndSetState(c, c + SHARED_UNIT)) {
                    //
                    if (sharedCount(c) == 0) {
                        firstReader = current;
                        firstReaderHoldCount = 1;
                    } else if (firstReader == current) {
                        firstReaderHoldCount++;
                    } else {
                        if (rh == null)
                            rh = cachedHoldCounter;
                        if (rh == null || rh.tid != getThreadId(current))
                            rh = readHolds.get();
                        else if (rh.count == 0)
                            readHolds.set(rh);
                        //重入數量累加
                        rh.count++;
                        //緩存計數器
                        cachedHoldCounter = rh; // cache for release
                    }
                    return 1;
                }
            }
        }

在這裏插入圖片描述
公平模式下直接讓下一個線程獲取鎖

        final boolean readerShouldBlock() {
            return hasQueuedPredecessors();
        }
    public final boolean hasQueuedPredecessors() {
        // The correctness of this depends on head being initialized
        // before tail and on head.next being accurate if the current
        // thread is first in queue.
        Node t = tail; // Read fields in reverse initialization order
        Node h = head;
        Node s;
        return h != t &&
            ((s = h.next) == null || s.thread != Thread.currentThread());
    }

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章