源码解读之(五)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(中)

ReentrantReadWriteLock是Java中的一个锁实现,它允许多个线程同时读取共享资源,但只允许一个线程写入共享资源。它是可重入的,也就是说,同一个线程可以多次获取读锁或写锁,而不会出现死锁。 ReentrantReadWriteLock源码实现比较复杂,主要包括两个内部类:Sync和FairSync。Sync是ReentrantReadWriteLock核心实现,它维护了读锁和写锁的状态,以及等待队列。FairSync是Sync的子类,它实现了公平锁的逻辑。 ReentrantReadWriteLock的读写锁是通过Sync类中的state字段实现的。state的高16位表示读锁的持有数量,低16位表示写锁的持有数量。当一个线程获取读锁时,它会增加state的高16位;当一个线程获取写锁时,它会增加state的低16位。当一个线程释放读锁或写锁时,它会减少相应的state值。 ReentrantReadWriteLock的等待队列是通过Sync类中的readQueues和writeQueue字段实现的。当一个线程请求读锁或写锁时,它会被加入到相应的等待队列中。当一个线程释放读锁或写锁时,它会唤醒等待队列中的一个线程。 ReentrantReadWriteLock的公平锁实现是通过FairSync类中的tryAcquireShared和tryAcquire方法实现的。tryAcquireShared方法用于获取读锁,它会先检查等待队列中是否有写锁请求,如果有,则返回失败;否则,它会尝试获取读锁。tryAcquire方法用于获取写锁,它会先检查等待队列中是否有读锁或写锁请求,如果有,则返回失败;否则,它会尝试获取写锁。 总的来说,ReentrantReadWriteLock是一个非常实用的锁实现,它可以提高多线程程序的并发性能。但是,由于它的实现比较复杂,使用时需要注意避免死锁和竞争条件等问题。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

老周聊架构

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值