ReentrantReadWriteLock.Sync::tryAcquireShared 源码笔记

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

private transient ThreadLocalHoldCounter readHolds;
private transient HoldCounter cachedHoldCounter;

// ReentrantReadWriteLock.Sync::tryAcquireShared
// 尝试获取读锁
@ReservedStackAccess
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();
    // 当前写锁已经被获取 且 获取写锁的线程不是本线程
    // 获取读锁失败
    // 此处判断失败有两种情况
    //  1.写锁没有被获取
    //  2.写锁被本线程持有
    //  这两种情况都可以尝试获取读锁
    if (exclusiveCount(c) != 0 &&
        getExclusiveOwnerThread() != current)
        return -1;
    
    int r = sharedCount(c);
    // 此处判断成功说明本线程获取读锁成功
    if (!readerShouldBlock() &&
        r < MAX_COUNT &&
        compareAndSetState(c, c + SHARED_UNIT)) {
        // r==0 说明读本线程是第一个获取读锁的线程
        if (r == 0) {
            firstReader = current;
            firstReaderHoldCount = 1;
        // firstReader==current 说明此次获取读锁为firstReader的重入
        } else if (firstReader == current) {
            firstReaderHoldCount++;
        } else {
            HoldCounter rh = cachedHoldCounter;
            // 判断成功说明当前缓存的HoldCounter不是本线程的
            if (rh == null ||
                rh.tid != LockSupport.getThreadId(current))
                cachedHoldCounter = rh = readHolds.get();
            // rh.count==0 时有可能本线程对应的ThreadLocalMap中已经没有了rh这个键
            // 为了保险其见需要重新配置一下
            else if (rh.count == 0)
                readHolds.set(rh);
            rh.count++;
        }
        return 1;
    }
    return fullTryAcquireShared(current);
}

 

posted @ 2021-05-19 13:28  榆木脑袋0v0  阅读(367)  评论(0)    收藏  举报