Java併發學習筆記16 AQS 之 ReentrantReadWriteLock

bilibili-Java併發學習筆記16 AQS 之 ReentrantReadWriteLock

基於 java 1.8.0

P48_可重入讀寫鎖底層源碼分析及思想探究

// ReadWriteLock 使用示例
package new_package.thread.p45;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
import java.util.stream.IntStream;

public class ReadWriteLockTest {

    ReadWriteLock readWriteLock = new ReentrantReadWriteLock();

    public void method1() {
        try {
            readWriteLock.readLock().lock();
            System.out.println("method1");
            TimeUnit.SECONDS.sleep(2);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            readWriteLock.readLock().unlock();
        }
    }

    public void method2() {
        try {
            readWriteLock.writeLock().lock();
            System.out.println("method2");
            TimeUnit.SECONDS.sleep(2);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            readWriteLock.writeLock().unlock();
        }
    }

    public static void main(String[] args) {
        ReadWriteLockTest demo = new ReadWriteLockTest();
        IntStream.range(0, 10).forEach(k -> new Thread(() -> {
            demo.method2();
        }).start());
    }
}
  1. 公平鎖與非公平鎖

類似 ReentrantLock ,在構造器中指定是否爲公平鎖,默認非公平模式;

// 默認非公平模式
ReadWriteLock readWriteLock = new ReentrantReadWriteLock();

// 指定爲公平模式
ReadWriteLock readWriteLock = new ReentrantReadWriteLock(true);
    /** Inner class providing readlock */
    private final ReentrantReadWriteLock.ReadLock readerLock;

    /** Inner class providing writelock */
    private final ReentrantReadWriteLock.WriteLock writerLock;

    /** Performs all synchronization mechanics */
    final Sync sync;

    public ReentrantReadWriteLock(boolean fair) {
        sync = fair ? new FairSync() : new NonfairSync();
        readerLock = new ReadLock(this);
        writerLock = new WriteLock(this);
    }
    // 關於同步器

    /**
     * ReentrantReadWriteLock 的內部類,同步器的實現
     * 子類有公平版本和非公平版本
     */
    abstract static class Sync extends AbstractQueuedSynchronizer {
        ///
    }

    /**
     * 非公平版本的 Sync
     */
    static final class NonfairSync extends Sync {
        private static final long serialVersionUID = -8159625535654395037L;
        final boolean writerShouldBlock() {
            return false; // writers can always barge
        }
        final boolean readerShouldBlock() {
            /* As a heuristic to avoid indefinite writer starvation,
             * block if the thread that momentarily appears to be head
             * of queue, if one exists, is a waiting writer.  This is
             * only a probabilistic effect since a new reader will not
             * block if there is a waiting writer behind other enabled
             * readers that have not yet drained from the queue.
             */
            return apparentlyFirstQueuedIsExclusive();
        }
    }

    /**
     * 公平版本的 Sync
     */
    static final class FairSync extends Sync {
        private static final long serialVersionUID = -2274990926593161451L;
        final boolean writerShouldBlock() {
            return hasQueuedPredecessors();
        }
        final boolean readerShouldBlock() {
            return hasQueuedPredecessors();
        }
    }
    // 關於讀寫鎖實現

    /**
     * ReentrantReadWriteLock 的內部類
     * The lock returned by method {@link ReentrantReadWriteLock#readLock}.
     */
    public static class ReadLock implements Lock, java.io.Serializable {
        private static final long serialVersionUID = -5992448646407690164L;
        private final Sync sync;

        /**
         * Constructor for use by subclasses
         *
         * @param lock the outer lock object
         * @throws NullPointerException if the lock is null
         */
        protected ReadLock(ReentrantReadWriteLock lock) {
            sync = lock.sync;
        }

        // ...
    }

    /**
     * ReentrantReadWriteLock 的內部類
     * The lock returned by method {@link ReentrantReadWriteLock#writeLock}.
     */
    public static class WriteLock implements Lock, java.io.Serializable {
        private static final long serialVersionUID = -4992448646407690164L;
        private final Sync sync;

        /**
         * Constructor for use by subclasses
         *
         * @param lock the outer lock object
         * @throws NullPointerException if the lock is null
         */
        protected WriteLock(ReentrantReadWriteLock lock) {
            sync = lock.sync;
        }

        // ...
    }
  1. 讀鎖的上鎖
    readWriteLock.readLock().lock();
    // 實現
    public void lock() {
        sync.acquireShared(1);
    }
    public final void acquireShared(int arg) {
        // 嘗試獲取共享鎖
        if (tryAcquireShared(arg) < 0)
            doAcquireShared(arg);
    }
        protected final int tryAcquireShared(int unused) {
            /*
             * Walkthrough:
             * 1. 如果另一個線程持有寫鎖,則失敗。
             * 2. 否則,此線程符合 lock wrt state 的條件,
             *    因此詢問它是否應該因爲隊列策略而阻塞。
             *    如果沒有,嘗試通過大小寫狀態和更新計數來授予。
             *    注意,step不檢查可重入獲取,它被推遲到完整版本,
             *    以避免在更典型的不可重入情況下檢查保留計數。
             * 3. 如果步驟2失敗是因爲線程明顯不合格、CAS失敗或計數飽和,
             *    則使用完整的重試循環鏈到版本。
             */
            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) {
                    // 共享鎖的佔有數不爲0
                    // 第一個獲取到此共享鎖的線程是本線程
                    firstReaderHoldCount++;
                } else {
                    // 共享鎖的佔有數不爲0 ,且 firstReader 不是當前線程
                    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);
        }
        // int 類型佔 4 byte,佔 32 bit (一半就是 16 bit)
        static final int SHARED_SHIFT   = 16;
        // 1 左移 16 位      :00000000 00000001 00000000 00000000
        static final int SHARED_UNIT    = (1 << SHARED_SHIFT);
        static final int MAX_COUNT      = (1 << SHARED_SHIFT) - 1;
        // (1 左移 16 位) -1 :00000000 00000000 11111111 11111111
        static final int EXCLUSIVE_MASK = (1 << SHARED_SHIFT) - 1;

        /**
         * 返回以count表示的共享保留數
         * state 無邏輯右移 16 位,即 state 的高16位
         */
        static int sharedCount(int c)    { return c >>> SHARED_SHIFT; }
        /**
         * 返回以count表示的獨佔保留數
         * state & 00000000 00000000 11111111 11111111 即:state 的低16位
         */
        static int exclusiveCount(int c) { return c & EXCLUSIVE_MASK; }

// <<  表示左移,不分正負數,低位補0;
// >>  表示右移,如果該數爲正,則高位補0,若爲負數,則高位補1;
// >>> 表示無符號右移,也叫邏輯右移,即無論該數爲正負,都是高位補0
    // Fair version of Sync
    final boolean readerShouldBlock() {
        // 等待隊列中是否還有前置節點
        return hasQueuedPredecessors();
    }

    // Nonfair version of Sync
    final boolean readerShouldBlock() {
        // 
        return apparentlyFirstQueuedIsExclusive();
    }

    final boolean apparentlyFirstQueuedIsExclusive() {
        Node h, s;
        return (h = head) != null &&
            (s = h.next)  != null &&
            !s.isShared()         &&
            s.thread != null;
    }
  1. 寫鎖的上鎖
    readWriteLock.writeLock().lock();
    public void lock() {
        sync.acquire(1);
    }
    public final void acquire(int arg) {
        // 嘗試獲取獨佔鎖
        // 若獲取失敗,則加入等待隊列
        if (!tryAcquire(arg) &&
            acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
            selfInterrupt();
    }
    // Sync in ReentrantReadWriteLock 的實現
    protected final boolean tryAcquire(int acquires) {
        /*
            * Walkthrough:
            * 1. 如果讀計數非零或寫入計數非零且所有者是不同的線程,則失敗。
            * 2. 如果計數飽和,則失敗。(只有當count已非零時纔會發生這種情況。)
            * 3. 否則,如果這個線程是可重入的獲取或隊列策略允許的話,它就有資格被鎖定。如果是,請更新狀態並設置所有者。
            */
        Thread current = Thread.currentThread();

        // state 的狀態
        int c = getState();
        // 獨佔鎖數量
        int w = exclusiveCount(c);

        // 
        if (c != 0) {
            // (Note: if c != 0 and w == 0 then shared count != 0)
            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))
            return false;
        setExclusiveOwnerThread(current);
        return true;
    }

P49_可重入讀寫鎖的共享鎖釋放源碼解析

  1. 讀鎖的釋放
    readWriteLock.readLock().unlock();
    public void unlock() {
        sync.releaseShared(1);
    }
    public final boolean releaseShared(int arg) {
        if (tryReleaseShared(arg)) {
            doReleaseShared();
            return true;
        }
        return false;
    }
    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;
            if (rh == null || rh.tid != getThreadId(current))
                rh = readHolds.get();
            int count = rh.count;
            if (count <= 1) {
                readHolds.remove();
                if (count <= 0)
                    throw unmatchedUnlockException();
            }
            --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.
                return nextc == 0;
        }
    }
  1. 寫鎖的釋放
    readWriteLock.writeLock().unlock();
    public void unlock() {
        sync.release(1);
    }
    // AQS
    public final boolean release(int arg) {
        if (tryRelease(arg)) {
            Node h = head;
            if (h != null && h.waitStatus != 0)
                unparkSuccessor(h);
            return true;
        }
        return false;
    }
        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;
        }

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