ReentrantReadWriteLock原始碼解析

寒武沒有紀發表於2018-10-10

ReentrantReadWriteLock 使用一個 32 位的 int 型別來表示鎖被佔用的執行緒數,高 16 位用來表示讀鎖佔有的執行緒數量,低 16 位表示寫鎖被同一個執行緒申請次數。

// 讀鎖佔用位數高16位
static final int SHARED_SHIFT   = 16;
// 增加讀鎖數量
static final int SHARED_UNIT    = (1 << SHARED_SHIFT);
// 申請讀鎖最大執行緒數量(65535)
static final int MAX_COUNT      = (1 << SHARED_SHIFT) - 1;
// 寫鎖重入次數
static final int EXCLUSIVE_MASK = (1 << SHARED_SHIFT) - 1;

// 當前執行緒持有讀鎖的重入次數,只在構造和readObject中初始化重入次數為0時刪除
private transient ThreadLocalHoldCounter readHolds;
// 最後一個獲取讀鎖執行緒的重入計數
private transient HoldCounter cachedHoldCounter;
// 第一個獲得讀鎖的執行緒
private transient Thread firstReader = null;
// 第一個獲得讀鎖的執行緒重入計數
private transient int firstReaderHoldCount;

ReentrantReadWriteLock 有公平鎖與非公平鎖實現,這裡主要看非公平鎖實現。

public ReentrantReadWriteLock() {
    this(false);
}

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

讀鎖加鎖

// ReentrantReadWriteLock.ReadLock
public void lock() {
    sync.acquireShared(1);
}
// AbstractQueuedSynchronizer
public final void acquireShared(int arg) {
    if (tryAcquireShared(arg) < 0)
        doAcquireShared(arg);
}
// ReentrantReadWriteLock
protected final int tryAcquireShared(int unused) {
    Thread current = Thread.currentThread();
    int c = getState();
    // 獨佔鎖的重入次數不等於0 且 獨佔鎖持有執行緒不等於當前執行緒,則返回-1獲取共享鎖失敗
    if (exclusiveCount(c) != 0 &&
        getExclusiveOwnerThread() != current)
        return -1;
    int r = sharedCount(c); // 持有共享鎖的執行緒數量
    // 判斷獲取讀鎖的執行緒是否需要阻塞 且 持有共享鎖執行緒數量小於最大執行緒數量 且 CAS設定持有共享鎖執行緒數量成功
    if (!readerShouldBlock() &&
        r < MAX_COUNT &&
        compareAndSetState(c, c + SHARED_UNIT)) {
        // 還沒有執行緒持有共享鎖
        if (r == 0) {
            firstReader = current; // 設定當前執行緒為第一個獲取共享鎖的執行緒
            firstReaderHoldCount = 1; // 第一個獲取讀鎖的執行緒重入次數設定為1
        } else if (firstReader == current) {
            // 第一個獲取共享鎖的執行緒與當前執行緒相同,則增加重入次數
            firstReaderHoldCount++; 
        } else {
            HoldCounter rh = cachedHoldCounter;
            // 最後一個獲取讀鎖執行緒的重入計數為空 或 其執行緒id與當前執行緒id不一致,則將當前執行緒的重入次數設定為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); // CAS失敗或其它原因則呼叫此方法處理
}
// ReentrantReadWriteLock
final int fullTryAcquireShared(Thread current) {

    HoldCounter rh = null;
    for (;;) {
        int c = getState();
        // 獨佔鎖的重入次數不等於0 且 獨佔鎖持有執行緒不等於當前執行緒,則返回-1獲取共享鎖失敗
        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;
        // 最後一個獲取讀鎖執行緒的重入計數為空 或 其執行緒id與當前執行緒id不一致
                    if (rh == null || rh.tid != getThreadId(current)) {
                        rh = readHolds.get();
            // 當前執行緒持有讀鎖的重入次數等於0,則移除改計數物件
                        if (rh.count == 0)
                            readHolds.remove();
                    }
                }
    // 重入次數為0,返回-1表示獲取共享鎖失敗
                if (rh.count == 0)
                    return -1;
            }
        }
        // 超過讀鎖最大執行緒數量丟擲異常
        if (sharedCount(c) == MAX_COUNT)
            throw new Error("Maximum lock count exceeded");
        // CAS設定持有共享鎖執行緒數量
        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;
        }
    }
}

讀鎖釋放

// ReentrantReadWriteLock
public void unlock() {
    sync.releaseShared(1);
}
// AbstractQueuedSynchronizer
public final boolean releaseShared(int arg) {
    if (tryReleaseShared(arg)) {
        doReleaseShared();
        return true;
    }
    return false;
}
// ReentrantReadWriteLock
protected final boolean tryReleaseShared(int unused) {
    Thread current = Thread.currentThread();
// 判斷第一個獲取讀鎖的執行緒與當前執行緒是否相同
    if (firstReader == current) {
        // assert firstReaderHoldCount > 0;
    // 如果重入次數為1,則直接置空firstReader
        if (firstReaderHoldCount == 1)
            firstReader = null;
        else
            firstReaderHoldCount--; // 重入次數自減
    } else {
        HoldCounter rh = cachedHoldCounter;
    // 最後一個獲取讀鎖執行緒的重入計數為空 或 其執行緒id與當前執行緒id不一致
        if (rh == null || rh.tid != getThreadId(current))
            rh = readHolds.get();
        int count = rh.count;
    // 如果當前執行緒的鎖重入次數<=1,則直接移除該計數物件
        if (count <= 1) {
            readHolds.remove();
            if (count <= 0)
                throw unmatchedUnlockException();
        }
        --rh.count; // 自減鎖重入次數
    }
    for (;;) {
        int c = getState();
        int nextc = c - SHARED_UNIT;
    // CAS設定同步state
        if (compareAndSetState(c, nextc)) 
            return nextc == 0;
    }
}

寫鎖加鎖

// ReentrantReadWriteLock.WriteLock
public void lock() {
    sync.acquire(1);
}
// AbstractQueuedSynchronizer
public final void acquire(int arg) {
    if (!tryAcquire(arg) &&
        acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
        selfInterrupt();
}
// ReentrantReadWriteLock.Sync
protected final boolean tryAcquire(int acquires) {
    Thread current = Thread.currentThread();
    int c = getState(); // 獲取當前同步狀態
    int w = exclusiveCount(c); // 獲取獨佔鎖的重入次數
// c不等於0說明當前讀鎖或寫鎖被佔用
    if (c != 0) {
        // (Note: if c != 0 and w == 0 then shared count != 0)
    // 獨佔鎖重入次數等於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;
    }
// 判斷寫鎖是否需要阻塞 或者 CAS設定state失敗,返回false獲取寫鎖失敗
    if (writerShouldBlock() ||
        !compareAndSetState(c, c + acquires))
        return false;
    setExclusiveOwnerThread(current); // 設定獨佔鎖持有物件為當前執行緒
    return true; // 獲取鎖成功
}

寫鎖釋放

// ReentrantReadWriteLock.WriteLock
public void unlock() {
    sync.release(1);
}
// AbstractQueuedSynchronizer
public final boolean release(int arg) {
    if (tryRelease(arg)) {
        Node h = head;
        if (h != null && h.waitStatus != 0)
            unparkSuccessor(h);
        return true;
    }
    return false;
}
// ReentrantReadWriteLock.Sync
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;
}

相關文章