并发编程(9)ReentrantReadWriteLock

读写锁,可以加读锁,也可以加写锁,适用于读多写少的场景。

如果有人在读数据,别人也能读数据。

如果有人在读数据,别人不能写数据。

如果有人在写数据,别人不能写数据。

如果有人在写数据,别人不能读数据。

读写状态的设计:

在这里插入图片描述

写锁加锁逻辑

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

public void lock() {
    sync.acquire(1);
}
public final void acquire(int arg) {
    if (!tryAcquire(arg) &&
        acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
        selfInterrupt();
}
protected final boolean tryAcquire(int acquires) {
   
    Thread current = Thread.currentThread();
    int c = getState();
    //写锁获取的次数,state二进制值的高16位代表了读锁,低16位代表了写锁。
    int w = exclusiveCount(c);
    //判断锁是否已经被占有
    if (c != 0) {
        //w == 0,说明有人加了读锁,没有人加写锁。加写锁失败。
        //w != 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;
    }
    //非公平锁,尝试加锁。设置state=1
    //公平锁,判断如果队列中有等待线程,就不加锁。
    if (writerShouldBlock() ||
        !compareAndSetState(c, c + acquires))
        return false;
    setExclusiveOwnerThread(current);
    return true;
}

读锁的加锁逻辑

读锁不是独占式锁,即同一时刻该锁可以被多个读线程获取也就是一种共享式锁。

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

public void lock() {
    sync.acquireShared(1);
}
public final void acquireShared(int arg) {
    if (tryAcquireShared(arg) < 0)
        doAcquireShared(arg);
}
protected final int tryAcquireShared(int unused) {

    Thread current = Thread.currentThread();
    int c = getState();
    //exclusiveCount(c) != 0,说明有人加了写锁,并且还不是当前线程加的,此时不能加读锁。
    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) {
            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 1;
    }
    //如果CAS失败或者已经获取读锁的线程再次获取读锁
    return fullTryAcquireShared(current);
}

猜你喜欢

转载自blog.csdn.net/qq40988670/article/details/86613429