JUC - ReentrantReadWriteLock 源碼分析

簡介

ReentrantReadWriteLock,讀寫鎖。維護了一對相關的鎖,一個用於只讀操作,另一個用於寫入操作。只要沒有 writer,讀取鎖可以由多個 reader 線程同時保持。寫入鎖是獨佔的。

與互斥鎖相比,讀-寫鎖允許對共享數據進行更高級別的併發訪問。雖然一次只有一個線程(writer 線程)可以修改共享數據,但在許多情況下,任何數量的線程可以同時讀取共享數據(reader 線程)。當訪問讀寫比恰當的共享數據時,使用讀-寫鎖所允許的併發性將帶來更大的性能提高。

源碼分析

ReentrantReadWriteLock的實現方式是在內部定義了一個實現AbstractQueuedSynchronizer(詳見:JUC 源碼分析 - AbstractQueuedSynchronizer(AQS))的內部類Sync,Sync同時實現了AbstractQueuedSynchronizer中獨佔模式的獲取和釋放方法tryAcquire和tryRelease,和共享模式的獲取和釋放方法tryAcquireShared和tryReleaseShared,寫鎖WriteLock使用獨佔模式的方法控制鎖狀態,讀鎖ReadLock使用共享模式的方法控制鎖狀態,在WriteLock和ReadLock中使用同一個AQS的子類Sync,用AQS的status代表讀寫鎖的狀態計數,單個int值,通過位運算區分高低位,低16位代表寫狀態,高16位代表讀狀態。支持公平非公平實現,支持中斷,支持重入,支持鎖降級。

當併發讀寫時:

  1. 當有線程獲取了獨佔鎖,那麼後續所有其他線程的獨佔和共享鎖請求會加入同步隊列等待,後續當前線程的獨佔和共享鎖可以再次獲取;
  2. 當有線程獲取了共享鎖,那麼後續所有線程的獨佔鎖請求會加入同步隊列,後續所有線程的共享鎖請求可以繼續獲取鎖;
  3. 當獨佔鎖完全釋放時,會喚醒後繼節點,當喚醒的是共享節點時,會傳播向後喚醒後繼的共享節點;
  4. 當共享鎖完全釋放時,且當前沒有持有獨佔鎖,會喚醒後繼節點,當喚醒的是共享節點時,會傳播向後喚醒後繼的共享節點;
  5. 噹噹前線程已經獲取獨佔鎖,那麼當前線程可以繼續獲取共享鎖,當獨佔鎖退出時,鎖降級爲共享鎖;
  6. 一個線程可以同時進入多次共享鎖或獨佔鎖;

Sync

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

        static final int SHARED_SHIFT   = 16;//32位分高16和低16位
        static final int SHARED_UNIT    = (1 << SHARED_SHIFT);//0000000000000001|0000000000000000
        static final int MAX_COUNT      = (1 << SHARED_SHIFT) - 1;//0000000000000000|1111111111111111
        static final int EXCLUSIVE_MASK = (1 << SHARED_SHIFT) - 1;//0000000000000000|1111111111111111

        static int sharedCount(int c)    { return c >>> SHARED_SHIFT; }//獲取共享鎖計數,高16位
        static int exclusiveCount(int c) { return c & EXCLUSIVE_MASK; }//獲取獨佔鎖計數,低16位

        static final class HoldCounter {//每個線程持有的讀鎖計數。寫鎖獨佔所以寫鎖的低16位就代表獨佔線程重入計數,讀鎖共享,所以讀鎖的高16代表所有線程所有重入次數的計數,HoldCounter用ThreadLocal保存每個線程自己的重入計數。
            int count = 0;
            final long tid = Thread.currentThread().getId();
        }

        static final class ThreadLocalHoldCounter
            extends ThreadLocal<HoldCounter> {
            public HoldCounter initialValue() {//初始化
                return new HoldCounter();
            }
        }

        private transient ThreadLocalHoldCounter readHolds;//保存每個線程持有的讀鎖計數,不參與序列化。

        private transient HoldCounter cachedHoldCounter;//緩存最新獲取共享鎖的線程的HoldCounter

        private transient Thread firstReader = null;//緩存第一個獲取共享鎖的線程
        private transient int firstReaderHoldCount;//緩存第一個獲取共享鎖的線程的重入計數

        Sync() {
            readHolds = new ThreadLocalHoldCounter();
            setState(getState()); //用volatile的讀寫保證readHolds的可見性,保證readHolds對所有線程可見。
        }

        abstract boolean readerShouldBlock();//共享鎖獲取是否需要阻塞。控制共享模式的獲取鎖操作是否公平,子類實現。公平實現會看當前同步隊列是否有有效的等待節點,有則返回true,沒有則返回false,直接嘗試獲取鎖;非公平實現查看隊列中的下一個節點是否是獨佔模式,是獨佔模式,則需要阻塞,避免寫鎖的獲取總是發生飢餓,否則,可以直接嘗試獲取鎖。

        abstract boolean writerShouldBlock();//獨佔鎖獲取是否需要阻塞。控制獨佔模式的獲取鎖操作是否公平,子類實現。公平實現會看當前同步隊列是否有有效的等待節點,有則返回true,需要加入同步隊列,順序獲取,沒有則返回false,直接嘗試獲取鎖;非公平實現返回false,代表不需要等待可以直接嘗試獲取鎖

        protected final boolean tryRelease(int releases) {//獨佔模式的釋放鎖
            if (!isHeldExclusively())//如果當前線程不是持有獨佔鎖的線程,將拋出異常
                throw new IllegalMonitorStateException();
            int nextc = getState() - releases;
            boolean free = exclusiveCount(nextc) == 0;//exclusiveCount方法檢查釋放後的狀態的低16位,是0則獨佔鎖完全釋放,設置當前持有獨佔鎖的線程位null
            if (free)
                setExclusiveOwnerThread(null);
            setState(nextc);//因爲是獨佔的釋放,所以直接set不會有問題。寫volatile,之前的所有內存操作會對所有線程可見,釋放之後其他線程才能獲取鎖。
            return free;//完全釋放獨佔鎖才返回true,這裏有可能是鎖降級,或者是讀寫鎖完全釋放。
        }

        protected final boolean tryAcquire(int acquires) {//獨佔模式的獲取鎖
            Thread current = Thread.currentThread();//獲取當前線程
            int c = getState();//獲取當前狀態
            int w = exclusiveCount(c);//獲取寫狀態
            if (c != 0) {//狀態不是0,則當前鎖已被獲取
                if (w == 0 || current != getExclusiveOwnerThread())//狀態不爲0,寫狀態爲0,說明讀狀態不爲0。即讀鎖被獲取或者當前線程不是持有獨佔鎖的線程,獲取獨佔鎖失敗,只有重入的獨佔鎖才能獲取
                    return false;
                if (w + exclusiveCount(acquires) > MAX_COUNT)//寫狀態超出16位的最大值則失敗拋出異常
                    throw new Error("Maximum lock count exceeded");
                setState(c + acquires);//執行到這裏說明狀態不爲0且寫狀態不爲0,說明獨佔鎖已經被獲取,且當前線程是持有獨佔鎖的線程,該獲取操作是重入獲取獨佔鎖
                return true;
            }
            //當前狀態爲0
            if (writerShouldBlock() //寫鎖是否需要等待,由子類實現,公平實現會看當前同步隊列是否有有效的等待節點,有則返回true,需要加入同步隊列,順序獲取,沒有則返回false,直接嘗試獲取鎖;非公平實現返回false,代表不需要等待可以直接嘗試獲取鎖
                || !compareAndSetState(c, c + acquires))//或CAS更新狀態失敗
                return false;//不可以直接獲取或者CAS更新狀態失敗,返回false
            setExclusiveOwnerThread(current);
            return true;//可以獲取鎖且CAS更新狀態成功,設置當前線程爲持有獨佔鎖的線程,返回true
        }

        protected final boolean tryReleaseShared(int unused) {//共享模式的釋放鎖
            Thread current = Thread.currentThread();
            if (firstReader == current) {
                if (firstReaderHoldCount == 1)
                    firstReader = null;
                else
                    firstReaderHoldCount--;
            } else {
                HoldCounter rh = cachedHoldCounter;
                if (rh == null || rh.tid != current.getId())
                    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;//狀態減去1左移16位的數,即讀狀態減一
                if (compareAndSetState(c, nextc))//CAS更新讀狀態成功
                    return nextc == 0;//如果更新後的狀態位爲0,代表讀寫鎖完全釋放,返回true。返回true纔會喚醒同步隊列中的線程
            }
        }

        private IllegalMonitorStateException unmatchedUnlockException() {
            return new IllegalMonitorStateException(
                "attempt to unlock read lock, not locked by current thread");
        }

        protected final int tryAcquireShared(int unused) {//共享模式的獲取鎖
            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)) {//如果讀鎖不需要阻塞,且讀狀態小於最大值,且讀狀態CAS增加成功,意味着獲取共享鎖成功
                if (r == 0) {//如果之前讀狀態是0,設置firstReader第一個讀線程爲當前線程,firstReaderHoldCount第一個讀線程獲取鎖計數1
                    firstReader = current;
                    firstReaderHoldCount = 1;
                } else if (firstReader == current) {//firstReader第一個讀線程爲當前線程,說明這次是重入的獲取共享鎖,firstReaderHoldCount第一個讀線程獲取鎖計數+1
                    firstReaderHoldCount++;
                } else {
                    HoldCounter rh = cachedHoldCounter;//緩存最後一個獲取共享鎖的線程狀態
                    if (rh == null || rh.tid != current.getId())
                        cachedHoldCounter = rh = readHolds.get();
                    else if (rh.count == 0)
                        readHolds.set(rh);
                    rh.count++;//readHolds保存每個線程持有的讀鎖計數
                }
                return 1;//獲取成功
            }
            //不可獲取
            return fullTryAcquireShared(current);
        }

        final int fullTryAcquireShared(Thread current) {
            HoldCounter rh = null;
            for (;;) {
                int c = getState();
                if (exclusiveCount(c) != 0) {//獨佔鎖被持有
                    if (getExclusiveOwnerThread() != current)//當前線程不是持有獨佔鎖的線程。返回-1
                        return -1;
                } else if (readerShouldBlock()) {//如果需要阻塞
                    if (firstReader == current) {
                    } else {
                        if (rh == null) {
                            rh = cachedHoldCounter;
                            if (rh == null || rh.tid != current.getId()) {
                                rh = readHolds.get();
                                if (rh.count == 0)
                                    readHolds.remove();
                            }
                        }
                        if (rh.count == 0)
                            return -1;
                    }
                }
                if (sharedCount(c) == MAX_COUNT)//共享鎖獲取已經達到最大計數
                    throw new Error("Maximum lock count exceeded");
                if (compareAndSetState(c, c + SHARED_UNIT)) {//CAS增加讀狀態成功
                    if (sharedCount(c) == 0) {//如果之前讀狀態是0,設置firstReader第一個讀線程爲當前線程,firstReaderHoldCount第一個讀線程獲取鎖計數1
                        firstReader = current;
                        firstReaderHoldCount = 1;
                    } else if (firstReader == current) {//firstReader第一個讀線程爲當前線程,說明這次是重入的獲取共享鎖,firstReaderHoldCount第一個讀線程獲取鎖計數+1
                        firstReaderHoldCount++;
                    } else {
                        if (rh == null)
                            rh = cachedHoldCounter;
                        if (rh == null || rh.tid != current.getId())
                            rh = readHolds.get();
                        else if (rh.count == 0)
                            readHolds.set(rh);
                        rh.count++;
                        cachedHoldCounter = rh; // cache for release
                    }
                    return 1;//獲取成功
                }
            }
        }

        final boolean tryWriteLock() {//僅當寫入鎖在調用期間未被另一個線程保持時獲取該鎖
            Thread current = Thread.currentThread();
            int c = getState();
            if (c != 0) {//狀態不爲0
                int w = exclusiveCount(c);
                if (w == 0 || current != getExclusiveOwnerThread())//寫狀態爲0或者當前線程不是持有獨佔鎖的線程
                    return false;
                if (w == MAX_COUNT)
                    throw new Error("Maximum lock count exceeded");
            }
            //寫狀態不爲0,且當前線程是持有獨佔鎖的線程
            if (!compareAndSetState(c, c + 1))
                return false;
            setExclusiveOwnerThread(current);
            return true;//CAS更新成功,設置當前線程爲持有獨佔鎖的線程,返回成功獲取
        }

        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)) {//循環CAS直到更新狀態成功,獲取到共享鎖
                    if (r == 0) {
                        firstReader = current;
                        firstReaderHoldCount = 1;
                    } else if (firstReader == current) {
                        firstReaderHoldCount++;
                    } else {
                        HoldCounter rh = cachedHoldCounter;
                        if (rh == null || rh.tid != current.getId())
                            cachedHoldCounter = rh = readHolds.get();
                        else if (rh.count == 0)
                            readHolds.set(rh);
                        rh.count++;
                    }
                    return true;
                }
            }
        }

        protected final boolean isHeldExclusively() {//當前線程是否是持有獨佔鎖的線程
            return getExclusiveOwnerThread() == Thread.currentThread();
        }

        // Methods relayed to outer class

        final ConditionObject newCondition() {//獨佔鎖可以獲取等待隊列
            return new ConditionObject();
        }

        final Thread getOwner() {//獲取當前持有獨佔鎖的線程
            return ((exclusiveCount(getState()) == 0) ?
                    null :
                    getExclusiveOwnerThread());
        }

        final int getReadLockCount() {//共享鎖計數
            return sharedCount(getState());
        }

        final boolean isWriteLocked() {//獨佔鎖是否被持有
            return exclusiveCount(getState()) != 0;
        }

        final int getWriteHoldCount() {//獲取當前線程持有的寫鎖計數
            return isHeldExclusively() ? exclusiveCount(getState()) : 0;
        }

        final int getReadHoldCount() {//獲取當前線程獲取共享鎖的重入計數
            if (getReadLockCount() == 0)
                return 0;

            Thread current = Thread.currentThread();
            if (firstReader == current)
                return firstReaderHoldCount;

            HoldCounter rh = cachedHoldCounter;
            if (rh != null && rh.tid == current.getId())
                return rh.count;

            int count = readHolds.get().count;
            if (count == 0) readHolds.remove();
            return count;
        }

        /**
         * Reconstitute this lock instance from a stream
         * @param s the stream
         */
        private void readObject(java.io.ObjectInputStream s)
            throws java.io.IOException, ClassNotFoundException {
            s.defaultReadObject();
            readHolds = new ThreadLocalHoldCounter();
            setState(0); // reset to unlocked state
        }

        final int getCount() { return getState(); }//獲取總讀寫狀態
    }

NonfairSync

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

    final boolean apparentlyFirstQueuedIsExclusive() {
        Node h, s;
        return (h = head) != null &&
            (s = h.next)  != null &&
            !s.isShared()         &&
            s.thread != null;
    }

FairSync

    static final class FairSync extends Sync {
        private static final long serialVersionUID = -2274990926593161451L;
        final boolean writerShouldBlock() {
            return hasQueuedPredecessors();
        }
        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());
    }

使用方式

public class ReadWriteLockTest {

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

    public String get(String key) {
        r.lock();
        try {
            return m.get(key);
        } finally {
            r.unlock();
        }
    }

    public String put(String key, String value) {
        w.lock();
        try {
            return m.put(key, value);
        } finally {
            w.unlock();
        }
    }

    public void clear() {
        w.lock();
        try {
            m.clear();
        } finally {
            w.unlock();
        }
    }

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