源碼解讀之(五)ReentrantReadWriteLock(上)

一、前言

Java併發包中常用的鎖(如:ReentrantLock),基本上都是排他鎖,這些鎖在同一時刻只允許一個線程進行訪問,而讀寫鎖在同一時刻可以允許多個讀線程訪問,但是在寫線程訪問時,所有的讀線程和其他寫線程均被阻塞。讀寫鎖維護了一對鎖,一個讀鎖和一個寫鎖,通過分離讀鎖和寫鎖,使得併發性相比一般的排他鎖有了很大提升。

相對於排他鎖,提高了併發性。在實際應用中,大部分情況下對共享數據(如緩存)的訪問都是讀操作遠多於寫操作,這時ReentrantReadWriteLock能夠提供比排他鎖更好的併發性和吞吐量。

二、ReentrantReadWriteLock

1、ReentrantReadWriteLock類包含三個核心變量:

  • readerLock:讀鎖。
  • writerLock:寫鎖。
  • sync:可以爲公平鎖FairSync 或 非公平鎖NonfairSync

2、ReentrantReadWriteLock類的構造函數執行以下幾件事情:

  • 新建鎖對象賦予ReentrantReadWriteLock的sync對象。
  • 將ReentrantReadWriteLock對象作爲this參數創建讀鎖ReadLock。
  • 將ReentrantReadWriteLock對象作爲this參數創建寫鎖WriteLock。
  • 在writerLock和ReadLock構造函數中將ReentrantReadWriteLock的sync對象賦值爲自身的sync對象,讀寫鎖的操作其實用的就是ReentrantReadWriteLock的sync對象。
// ReentrantReadWriteLock本身不提供加鎖服務,只負責提供讀鎖和寫鎖
public class ReentrantReadWriteLock implements ReadWriteLock, java.io.Serializable {
    private final ReentrantReadWriteLock.ReadLock readerLock;
    private final ReentrantReadWriteLock.WriteLock writerLock;
    final Sync sync;

    public ReentrantReadWriteLock() {
        this(false);
    }

    public ReentrantReadWriteLock(boolean fair) {
        sync = fair ? new FairSync() : new NonfairSync();
        readerLock = new ReadLock(this);
        writerLock = new WriteLock(this);
    }

    public ReentrantReadWriteLock.WriteLock writeLock() { return writerLock; } // 寫鎖
    public ReentrantReadWriteLock.ReadLock  readLock()  { return readerLock; } // 讀鎖

    // 總的讀鎖計數
    public int getReadLockCount() {
        return sync.getReadLockCount();
    }

    // 當前線程的寫鎖計數(當前線程必須佔有鎖)
    public int getWriteHoldCount() {
        return sync.getWriteHoldCount();
    }

    // 當前線程的讀鎖計數
    public int getReadHoldCount() {
        return sync.getReadHoldCount();
    }

    // 獲取所有在SyncQueue中排隊的寫線程
    protected Collection<Thread> getQueuedWriterThreads() {
        return sync.getExclusiveQueuedThreads();
    }

    // 獲取所有在SyncQueue中排隊的讀線程
    protected Collection<Thread> getQueuedReaderThreads() {
        return sync.getSharedQueuedThreads();
    }

    ... ...

    static final long getThreadId(Thread thread) {
        return UNSAFE.getLongVolatile(thread, TID_OFFSET); // tid在Thread類中非volatile
    }

    private static final sun.misc.Unsafe UNSAFE;
    private static final long TID_OFFSET;
    static {
        try {
            UNSAFE = sun.misc.Unsafe.getUnsafe();
            Class<?> tk = Thread.class;
            TID_OFFSET = UNSAFE.objectFieldOffset
                (tk.getDeclaredField("tid"));
        } catch (Exception e) {
            throw new Error(e);
        }
    }

}

3、ReadLock

  • ReadLock的構造函數入參爲ReentrantReadWriteLock對象,通過將ReentrantReadWriteLock對象的sync對象賦值給ReadLock的Sync。
  • ReadLock的lock和unlock操作都通過sync對象來實現加鎖和解鎖。
public static class ReadLock implements Lock, java.io.Serializable {
    private static final long serialVersionUID = -5992448646407690164L;
    private final Sync sync;

    protected ReadLock(ReentrantReadWriteLock lock) {
        sync = lock.sync;
    }

    public void lock() { // 加讀鎖
        sync.acquireShared(1);
    }

    public void lockInterruptibly() throws InterruptedException { // 加讀鎖(可被中斷)
        sync.acquireSharedInterruptibly(1);
    }

    public boolean tryLock() { // 嘗試加讀鎖
        return sync.tryReadLock();
    }

    public boolean tryLock(long timeout, TimeUnit unit)
            throws InterruptedException { // 加讀鎖(在timeOut內等鎖)
        return sync.tryAcquireSharedNanos(1, unit.toNanos(timeout));
    }

    public void unlock() { // 釋放讀鎖
        sync.releaseShared(1);
    }

    public Condition newCondition() { // 拋出不支持的條件異常
        throw new UnsupportedOperationException();
    }
    
	public String toString() { // 返回標識此鎖的字符串及其鎖定狀態
        int r = sync.getReadLockCount();
        return super.toString() +
            "[Read locks = " + r + "]";
    }
}

4、WriteLock

  • WriteLock的構造函數入參爲ReentrantReadWriteLock對象,通過將ReentrantReadWriteLock對象的sync對象賦值給ReadLock的Sync。
  • WriteLock的lock和unlock操作都通過sync對象來實現加鎖和解鎖。
public static class WriteLock implements Lock, java.io.Serializable {
    private final Sync sync;

    protected WriteLock(ReentrantReadWriteLock lock) {
        sync = lock.sync;
    }

    public void lock() { // 加寫鎖
        sync.acquire(1);
    }

    public void lockInterruptibly() throws InterruptedException { // 加寫鎖(可被中斷)
        sync.acquireInterruptibly(1);
    }

    public boolean tryLock( ) { // 嘗試加寫鎖
        return sync.tryWriteLock();
    }

    public boolean tryLock(long timeout, TimeUnit unit) throws InterruptedException { // 加寫鎖(在timeOut內等鎖)
        return sync.tryAcquireNanos(1, unit.toNanos(timeout));
    }

    public void unlock() { // 釋放寫鎖
        sync.release(1);
    }

	public Condition newCondition() {
        return sync.newCondition();
    }

    public String toString() { // 返回標識此鎖的字符串及其lock狀態
        Thread o = sync.getOwner();
        return super.toString() + ((o == null) ?
                                   "[Unlocked]" :
                                   "[Locked by thread " + o.getName() + "]");
}

5、Sync

  • 公平鎖FairSync和非公平鎖NonfairSync屬於ReentrantReadWriteLock內部定義類,繼承自Sync類。
  • Sync類繼承自AbstractQueuedSynchronizer類,Sync類有一些核心的變量已經加註釋。
  • AQS的state變量32位分開高16位爲讀狀態,低16位爲寫狀態。
static final class NonfairSync extends Sync {
	private static final long serialVersionUID = -8159625535654395037L;
    final boolean writerShouldBlock() { // 寫線程永遠可以搶鎖
        return false;
    }
    final boolean readerShouldBlock() { // SyncQueue排隊的第一個節點(head.next)爲寫節點佔鎖時必須排隊
        return apparentlyFirstQueuedIsExclusive();
    }
}
final boolean apparentlyFirstQueuedIsExclusive() {
    Node h, s;
    return (h = head) != null &&
        (s = h.next)  != null &&
        !s.isShared()         &&
        s.thread != null;
}
static final class FairSync extends Sync {
	private static final long serialVersionUID = -2274990926593161451L;
    final boolean writerShouldBlock() { // SyncQueue中下個待喚醒節點不是當前線程時必須排隊
        return hasQueuedPredecessors();
    }
    final boolean readerShouldBlock() { // SyncQueue中下個待喚醒節點不是當前線程時必須排隊
        return hasQueuedPredecessors();
    }
}
public final boolean hasQueuedPredecessors() {
    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());
}
static final class Node {
    // 正在等待的共享鎖
    static final Node SHARED = new Node();
    // 正在等待的獨佔鎖
    static final Node EXCLUSIVE = null;

    // 等待狀態取消
    static final int CANCELLED =  1;
    // 等待狀態喚醒
    static final int SIGNAL    = -1;
    // 等待狀態條件
    static final int CONDITION = -2;
    // 無條件傳播
    static final int PROPAGATE = -3;

    // 等待狀態
    volatile int waitStatus;

    // 前驅節點
    volatile Node prev;

    // 後驅節點
    volatile Node next;

    volatile Thread thread;

    // 鏈接到等待條件的下一個節點
    Node nextWaiter;

    // 如果節點在共享模式下等待,則返回true
    final boolean isShared() {
        return nextWaiter == SHARED;
    }

    // 返回上一個節點,如果爲null則拋出NullPointerException。
    final Node predecessor() throws NullPointerException {
        Node p = prev;
        if (p == null)
            throw new NullPointerException();
        else
            return p;
    }

    Node() {    // 用於初始頭部和共享標記
    }

    Node(Thread thread, Node mode) {     // 由addWaiter模式使用
        this.nextWaiter = mode;
        this.thread = thread;
    }

    Node(Thread thread, int waitStatus) { // 由條件使用
        this.waitStatus = waitStatus;
        this.thread = thread;
    }
}

核心類Sync,,這個類小夥伴們可以多花點時間研究下。

讀寫狀態的設計

讀寫鎖同樣依賴自定義同步器來實現同步功能,而讀寫狀態就是其同步器的同步狀態。回想ReentrantLock中自定義同步器的實現,同步狀態表示鎖被一個線程重複獲取的次數,而讀寫鎖的自定義同步器需要在同步狀態(一個整型變量)上維護多個讀線程和一個寫線程的狀態,使得該狀態的設計成爲讀寫鎖實現的關鍵。

如果在一個整型變量上維護多種狀態,就一定需要“按位切割使用”這個變量,讀寫鎖是將變量切分成了兩個部分,高16位表示讀,低16位表示寫,劃分方式如圖所示。

在這裏插入圖片描述

如圖所示,當前同步狀態表示一個線程已經獲取了寫鎖,且重進入了兩次,同時也連續獲取了兩次讀鎖。讀寫鎖是如何迅速的確定讀和寫各自的狀態呢?答案是通過位運算。假設當前同步狀態值爲S,寫狀態等於 S & 0x0000FFFF(將高16位全部抹去),讀狀態等於 S >>> 16(無符號補0右移16位)。當寫狀態增加1時,等於S + 1,當讀狀態增加1時,等於S + (1 << 16),也就是S + 0x00010000。

根據狀態的劃分能得出一個推論:S不等於0時,當寫狀態(S & 0x0000FFFF)等於0時,則讀狀態(S >>> 16)大於0,即讀鎖已被獲取。

abstract static class Sync extends AbstractQueuedSynchronizer {
    static final int SHARED_SHIFT   = 16; // state高16位爲讀鎖計數,state低16位爲寫鎖計數
    static final int SHARED_UNIT    = (1 << SHARED_SHIFT); // 讀鎖計數 + 1
    static final int MAX_COUNT      = (1 << SHARED_SHIFT) - 1; // 讀(寫)鎖計數 <= 2^16 - 1
    static final int EXCLUSIVE_MASK = (1 << SHARED_SHIFT) - 1; // 寫鎖計數 = state & (2^16 - 1)

    Sync() {
        readHolds = new ThreadLocalHoldCounter();
        setState(getState()); // 確保readHolds的可見性
    }

    // return 鎖狀態(鎖計數)
    final int getCount() { return getState(); }

    // 總的讀鎖計數
    final int getReadLockCount() {
        return sharedCount(getState());
    }
    static int sharedCount(int c)    { return c >>> SHARED_SHIFT; }

    // 當前線程的寫鎖計數(當前線程必須佔有鎖)
    final int getWriteHoldCount() {
        return isHeldExclusively() ? exclusiveCount(getState()) : 0;
    }
    static int exclusiveCount(int c) { return c & EXCLUSIVE_MASK; }

    // 當前線程的讀鎖計數
    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 == getThreadId(current))
            return rh.count;

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

    private transient ThreadLocalHoldCounter readHolds; // 當前線程的讀鎖計數
    private transient HoldCounter cachedHoldCounter; // 緩存的線程讀鎖計數
    private transient Thread firstReader = null; // 首個讀線程
    private transient int firstReaderHoldCount; // 首個讀線程的讀鎖計數

    static final class HoldCounter {
        int count = 0;
        // tid在Thread類中非volatile
        // Thread.getId -> UNSAFE.getLongVolatile(Thread.currentThread(), Thread.class.getDeclaredField("tid"))
        final long tid = getThreadId(Thread.currentThread());
    }

    static final class ThreadLocalHoldCounter extends ThreadLocal<HoldCounter> {
        public HoldCounter initialValue() {
            return new HoldCounter(); // {0, currentThreadId}
        }
    }

    // 嘗試取寫鎖
    protected final boolean tryAcquire(int acquires) {
        Thread current = Thread.currentThread();
        int c = getState();                         /*記錄state*/
        int w = exclusiveCount(c); // 寫鎖計數w
        if (c != 0) {// 讀線程未釋放鎖 || 當前線程不是鎖的獨佔者
            if (w == 0 || current != getExclusiveOwnerThread())
                return false; // 取鎖失敗
            // 當前線程已佔有鎖(Reentrant)
            if (w + exclusiveCount(acquires) > MAX_COUNT)
                throw new Error("Maximum lock count exceeded");
            setState(c + acquires); // 更新鎖狀態,寫鎖計數++
            return true; // 成功取鎖(已佔有鎖)
        }
        // state == 0
        if (writerShouldBlock() || // false(NonfairSync)|| hasQueuedPredecessors(FairSync)
            !compareAndSetState(c, c + acquires))   /*CAS設置state += acquires*/
            // CAS(state)失敗
            return false; // 取鎖失敗
        // CAS(state)成功
        setExclusiveOwnerThread(current); // 設置當前線程爲鎖的獨佔者
        return true; // 成功取鎖
    }

    // 嘗試搶寫鎖,不進行writerShouldBlock判斷
    final boolean tryWriteLock() {
        Thread current = Thread.currentThread();
        int c = getState();
        if (c != 0) {
            int w = exclusiveCount(c);  // 寫鎖計數w
            // 讀線程未釋放鎖 || 當前線程不是鎖的獨佔者
            if (w == 0 || current != getExclusiveOwnerThread())
                return false;
            // 當前線程已佔有鎖(Reentrant)
            if (w == MAX_COUNT)
                throw new Error("Maximum lock count exceeded");
        }
        if (!compareAndSetState(c, c + 1)) // CAS設置state += 1
            // CAS(state)失敗
            return false; // 搶鎖失敗
        // CAS(state)成功
        setExclusiveOwnerThread(current);
        return true; // 搶鎖成功
    }

    // 嘗試取讀鎖
    protected final int tryAcquireShared(int unused) {
        Thread current = Thread.currentThread();
        int c = getState();                             /*記錄state*/
        // 寫線程未釋放鎖 && 未釋放鎖的寫線程非當前線程(讀寫線程可爲同一線程)
        if (exclusiveCount(c) != 0 && getExclusiveOwnerThread() != current) 
            return -1; // 取鎖失敗
        int r = sharedCount(c); // 讀鎖計數r
        if (!readerShouldBlock() && // apparentlyFirstQueuedIsExclusive(NonfairSync)|| hasQueuedPredecessors(FairSync)
            r < MAX_COUNT && // r未超過閾值
            compareAndSetState(c, c + SHARED_UNIT)) {   /*CAS設置state += SHARED_UNIT*/ // 讀鎖計數++
            // CAS(state)成功
            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) // 緩存的是當前線程的讀鎖計數,而當前線程的讀鎖計數在上次release時被刪除
                    readHolds.set(rh);
                rh.count++;
            }
            return 1; // 成功取鎖
        }
        // CAS(state)失敗
        return fullTryAcquireShared(current);
    }

    // 不斷嘗試取讀鎖,直到取鎖失敗(寫線程佔有鎖 || 當前線程的讀鎖計數爲0) || 成功取鎖
    final int fullTryAcquireShared(Thread current) {
        HoldCounter rh = null;
        for (;;) {
            // 當前線程的讀鎖計數不爲0 && CAS(state)失敗將回到此處
            int c = getState();                             /*記錄state*/
            if (exclusiveCount(c) != 0) { // 寫線程未釋放鎖
                if (getExclusiveOwnerThread() != current) // 當前線程不是鎖的獨佔者
                    return -1;// 取鎖失敗
            } else if (readerShouldBlock()) {
                if (firstReader == current) {
                } else {
                    if (rh == null) {
                        rh = cachedHoldCounter;
                        if (rh == null || rh.tid != getThreadId(current)) {
                            rh = readHolds.get();
                            if (rh.count == 0) // 當前線程的讀鎖計數爲0
                                readHolds.remove(); // 在線程局部變量中刪除當前線程的讀鎖計數
                        }
                    }
                    if (rh.count == 0) // 當前線程的讀鎖計數爲0
                        return -1; // 應排隊取鎖
                    // 繼續嘗試取鎖
                }
            }
            if (sharedCount(c) == MAX_COUNT)
                throw new Error("Maximum lock count exceeded");
            if (compareAndSetState(c, c + SHARED_UNIT)) {   /*CAS設置state += SHARED_UNIT*/
                // CAS(state)成功
                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; // 成功取鎖
            }
            // CAS(state)失敗
        }
    }

    // 嘗試搶讀鎖,不進行readerShouldBlock判斷
    final boolean tryReadLock() {
        Thread current = Thread.currentThread();
        for (;;) {
            // CAS(state)失敗將回到此處
            int c = getState();                             /*記錄state*/
            // 寫線程未釋放鎖 && 未釋放鎖的寫線程非當前線程(讀寫線程可爲同一線程)
            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設置state += SHARED_UNIT*/
                // CAS(state)成功
                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; // 成功搶鎖
            }
            // CAS(state)失敗
        }
    }

    // 嘗試釋放寫鎖
    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;
    }

    // 嘗試釋放讀鎖
    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 (;;) {
            // CAS(state)失敗將回到此處
            int c = getState();                 /*記錄state*/
            int nextc = c - SHARED_UNIT; // 讀鎖計數--
            if (compareAndSetState(c, nextc))   /*CAS設置state = nextc*/
                // CAS(state)成功
                return nextc == 0;
            // CAS(state)失敗
        }
    }

    ... ...
}

下一篇 中篇主要來講解講解ReentrantReadWriteLockReadLock的加鎖和減鎖過程:
源碼解讀之(五)ReentrantReadWriteLock(中)

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