JUC - ReentrantReadWriteLock 源码分析

简介

ReentrantReadWriteLock,读写锁。维护了一对相关的锁,一个用于只读操作,另一个用于写入操作。只要没有 writer,读取锁可以由多个 reader 线程同时保持。写入锁是独占的。

与互斥锁相比,读-写锁允许对共享数据进行更高级别的并发访问。虽然一次只有一个线程(writer 线程)可以修改共享数据,但在许多情况下,任何数量的线程可以同时读取共享数据(reader 线程)。当访问读写比恰当的共享数据时,使用读-写锁所允许的并发性将带来更大的性能提高。

源码分析

ReentrantReadWriteLock的实现方式是在内部定义了一个实现AbstractQueuedSynchronizer(详见:JUC 源码分析 - AbstractQueuedSynchronizer(AQS))的内部类Sync,Sync同时实现了AbstractQueuedSynchronizer中独占模式的获取和释放方法tryAcquire和tryRelease,和共享模式的获取和释放方法tryAcquireShared和tryReleaseShared,写锁WriteLock使用独占模式的方法控制锁状态,读锁ReadLock使用共享模式的方法控制锁状态,在WriteLock和ReadLock中使用同一个AQS的子类Sync,用AQS的status代表读写锁的状态计数,单个int值,通过位运算区分高低位,低16位代表写状态,高16位代表读状态。支持公平非公平实现,支持中断,支持重入,支持锁降级。

当并发读写时:

  1. 当有线程获取了独占锁,那么后续所有其他线程的独占和共享锁请求会加入同步队列等待,后续当前线程的独占和共享锁可以再次获取;
  2. 当有线程获取了共享锁,那么后续所有线程的独占锁请求会加入同步队列,后续所有线程的共享锁请求可以继续获取锁;
  3. 当独占锁完全释放时,会唤醒后继节点,当唤醒的是共享节点时,会传播向后唤醒后继的共享节点;
  4. 当共享锁完全释放时,且当前没有持有独占锁,会唤醒后继节点,当唤醒的是共享节点时,会传播向后唤醒后继的共享节点;
  5. 当当前线程已经获取独占锁,那么当前线程可以继续获取共享锁,当独占锁退出时,锁降级为共享锁;
  6. 一个线程可以同时进入多次共享锁或独占锁;

Sync

    abstract static class Sync extends AbstractQueuedSynchronizer {
        private static final long serialVersionUID = 6317671515068378041L;

        static final int SHARED_SHIFT   = 16;//32位分高16和低16位
        static final int SHARED_UNIT    = (1 << SHARED_SHIFT);//0000000000000001|0000000000000000
        static final int MAX_COUNT      = (1 << SHARED_SHIFT) - 1;//0000000000000000|1111111111111111
        static final int EXCLUSIVE_MASK = (1 << SHARED_SHIFT) - 1;//0000000000000000|1111111111111111

        static int sharedCount(int c)    { return c >>> SHARED_SHIFT; }//获取共享锁计数,高16位
        static int exclusiveCount(int c) { return c & EXCLUSIVE_MASK; }//获取独占锁计数,低16位

        static final class HoldCounter {//每个线程持有的读锁计数。写锁独占所以写锁的低16位就代表独占线程重入计数,读锁共享,所以读锁的高16代表所有线程所有重入次数的计数,HoldCounter用ThreadLocal保存每个线程自己的重入计数。
            int count = 0;
            final long tid = Thread.currentThread().getId();
        }

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

        private transient ThreadLocalHoldCounter readHolds;//保存每个线程持有的读锁计数,不参与序列化。

        private transient HoldCounter cachedHoldCounter;//缓存最新获取共享锁的线程的HoldCounter

        private transient Thread firstReader = null;//缓存第一个获取共享锁的线程
        private transient int firstReaderHoldCount;//缓存第一个获取共享锁的线程的重入计数

        Sync() {
            readHolds = new ThreadLocalHoldCounter();
            setState(getState()); //用volatile的读写保证readHolds的可见性,保证readHolds对所有线程可见。
        }

        abstract boolean readerShouldBlock();//共享锁获取是否需要阻塞。控制共享模式的获取锁操作是否公平,子类实现。公平实现会看当前同步队列是否有有效的等待节点,有则返回true,没有则返回false,直接尝试获取锁;非公平实现查看队列中的下一个节点是否是独占模式,是独占模式,则需要阻塞,避免写锁的获取总是发生饥饿,否则,可以直接尝试获取锁。

        abstract boolean writerShouldBlock();//独占锁获取是否需要阻塞。控制独占模式的获取锁操作是否公平,子类实现。公平实现会看当前同步队列是否有有效的等待节点,有则返回true,需要加入同步队列,顺序获取,没有则返回false,直接尝试获取锁;非公平实现返回false,代表不需要等待可以直接尝试获取锁

        protected final boolean tryRelease(int releases) {//独占模式的释放锁
            if (!isHeldExclusively())//如果当前线程不是持有独占锁的线程,将抛出异常
                throw new IllegalMonitorStateException();
            int nextc = getState() - releases;
            boolean free = exclusiveCount(nextc) == 0;//exclusiveCount方法检查释放后的状态的低16位,是0则独占锁完全释放,设置当前持有独占锁的线程位null
            if (free)
                setExclusiveOwnerThread(null);
            setState(nextc);//因为是独占的释放,所以直接set不会有问题。写volatile,之前的所有内存操作会对所有线程可见,释放之后其他线程才能获取锁。
            return free;//完全释放独占锁才返回true,这里有可能是锁降级,或者是读写锁完全释放。
        }

        protected final boolean tryAcquire(int acquires) {//独占模式的获取锁
            Thread current = Thread.currentThread();//获取当前线程
            int c = getState();//获取当前状态
            int w = exclusiveCount(c);//获取写状态
            if (c != 0) {//状态不是0,则当前锁已被获取
                if (w == 0 || current != getExclusiveOwnerThread())//状态不为0,写状态为0,说明读状态不为0。即读锁被获取或者当前线程不是持有独占锁的线程,获取独占锁失败,只有重入的独占锁才能获取
                    return false;
                if (w + exclusiveCount(acquires) > MAX_COUNT)//写状态超出16位的最大值则失败抛出异常
                    throw new Error("Maximum lock count exceeded");
                setState(c + acquires);//执行到这里说明状态不为0且写状态不为0,说明独占锁已经被获取,且当前线程是持有独占锁的线程,该获取操作是重入获取独占锁
                return true;
            }
            //当前状态为0
            if (writerShouldBlock() //写锁是否需要等待,由子类实现,公平实现会看当前同步队列是否有有效的等待节点,有则返回true,需要加入同步队列,顺序获取,没有则返回false,直接尝试获取锁;非公平实现返回false,代表不需要等待可以直接尝试获取锁
                || !compareAndSetState(c, c + acquires))//或CAS更新状态失败
                return false;//不可以直接获取或者CAS更新状态失败,返回false
            setExclusiveOwnerThread(current);
            return true;//可以获取锁且CAS更新状态成功,设置当前线程为持有独占锁的线程,返回true
        }

        protected final boolean tryReleaseShared(int unused) {//共享模式的释放锁
            Thread current = Thread.currentThread();
            if (firstReader == current) {
                if (firstReaderHoldCount == 1)
                    firstReader = null;
                else
                    firstReaderHoldCount--;
            } else {
                HoldCounter rh = cachedHoldCounter;
                if (rh == null || rh.tid != current.getId())
                    rh = readHolds.get();
                int count = rh.count;
                if (count <= 1) {
                    readHolds.remove();
                    if (count <= 0)
                        throw unmatchedUnlockException();
                }
                --rh.count;
            }
            for (;;) {
                int c = getState();
                int nextc = c - SHARED_UNIT;//状态减去1左移16位的数,即读状态减一
                if (compareAndSetState(c, nextc))//CAS更新读状态成功
                    return nextc == 0;//如果更新后的状态位为0,代表读写锁完全释放,返回true。返回true才会唤醒同步队列中的线程
            }
        }

        private IllegalMonitorStateException unmatchedUnlockException() {
            return new IllegalMonitorStateException(
                "attempt to unlock read lock, not locked by current thread");
        }

        protected final int tryAcquireShared(int unused) {//共享模式的获取锁
            Thread current = Thread.currentThread();
            int c = getState();
            if (exclusiveCount(c) != 0 &&
                getExclusiveOwnerThread() != current)//独占锁被持有,且当前线程不是持有独占锁的线程,返回不可获取
                return -1;
            int r = sharedCount(c);//读状态
            if (!readerShouldBlock() &&
                r < MAX_COUNT &&
                compareAndSetState(c, c + SHARED_UNIT)) {//如果读锁不需要阻塞,且读状态小于最大值,且读状态CAS增加成功,意味着获取共享锁成功
                if (r == 0) {//如果之前读状态是0,设置firstReader第一个读线程为当前线程,firstReaderHoldCount第一个读线程获取锁计数1
                    firstReader = current;
                    firstReaderHoldCount = 1;
                } else if (firstReader == current) {//firstReader第一个读线程为当前线程,说明这次是重入的获取共享锁,firstReaderHoldCount第一个读线程获取锁计数+1
                    firstReaderHoldCount++;
                } else {
                    HoldCounter rh = cachedHoldCounter;//缓存最后一个获取共享锁的线程状态
                    if (rh == null || rh.tid != current.getId())
                        cachedHoldCounter = rh = readHolds.get();
                    else if (rh.count == 0)
                        readHolds.set(rh);
                    rh.count++;//readHolds保存每个线程持有的读锁计数
                }
                return 1;//获取成功
            }
            //不可获取
            return fullTryAcquireShared(current);
        }

        final int fullTryAcquireShared(Thread current) {
            HoldCounter rh = null;
            for (;;) {
                int c = getState();
                if (exclusiveCount(c) != 0) {//独占锁被持有
                    if (getExclusiveOwnerThread() != current)//当前线程不是持有独占锁的线程。返回-1
                        return -1;
                } else if (readerShouldBlock()) {//如果需要阻塞
                    if (firstReader == current) {
                    } else {
                        if (rh == null) {
                            rh = cachedHoldCounter;
                            if (rh == null || rh.tid != current.getId()) {
                                rh = readHolds.get();
                                if (rh.count == 0)
                                    readHolds.remove();
                            }
                        }
                        if (rh.count == 0)
                            return -1;
                    }
                }
                if (sharedCount(c) == MAX_COUNT)//共享锁获取已经达到最大计数
                    throw new Error("Maximum lock count exceeded");
                if (compareAndSetState(c, c + SHARED_UNIT)) {//CAS增加读状态成功
                    if (sharedCount(c) == 0) {//如果之前读状态是0,设置firstReader第一个读线程为当前线程,firstReaderHoldCount第一个读线程获取锁计数1
                        firstReader = current;
                        firstReaderHoldCount = 1;
                    } else if (firstReader == current) {//firstReader第一个读线程为当前线程,说明这次是重入的获取共享锁,firstReaderHoldCount第一个读线程获取锁计数+1
                        firstReaderHoldCount++;
                    } else {
                        if (rh == null)
                            rh = cachedHoldCounter;
                        if (rh == null || rh.tid != current.getId())
                            rh = readHolds.get();
                        else if (rh.count == 0)
                            readHolds.set(rh);
                        rh.count++;
                        cachedHoldCounter = rh; // cache for release
                    }
                    return 1;//获取成功
                }
            }
        }

        final boolean tryWriteLock() {//仅当写入锁在调用期间未被另一个线程保持时获取该锁
            Thread current = Thread.currentThread();
            int c = getState();
            if (c != 0) {//状态不为0
                int w = exclusiveCount(c);
                if (w == 0 || current != getExclusiveOwnerThread())//写状态为0或者当前线程不是持有独占锁的线程
                    return false;
                if (w == MAX_COUNT)
                    throw new Error("Maximum lock count exceeded");
            }
            //写状态不为0,且当前线程是持有独占锁的线程
            if (!compareAndSetState(c, c + 1))
                return false;
            setExclusiveOwnerThread(current);
            return true;//CAS更新成功,设置当前线程为持有独占锁的线程,返回成功获取
        }

        final boolean tryReadLock() {//仅当写入锁在调用期间未被另一个线程保持时获取读取锁。
            Thread current = Thread.currentThread();
            for (;;) {
                int c = getState();
                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直到更新状态成功,获取到共享锁
                    if (r == 0) {
                        firstReader = current;
                        firstReaderHoldCount = 1;
                    } else if (firstReader == current) {
                        firstReaderHoldCount++;
                    } else {
                        HoldCounter rh = cachedHoldCounter;
                        if (rh == null || rh.tid != current.getId())
                            cachedHoldCounter = rh = readHolds.get();
                        else if (rh.count == 0)
                            readHolds.set(rh);
                        rh.count++;
                    }
                    return true;
                }
            }
        }

        protected final boolean isHeldExclusively() {//当前线程是否是持有独占锁的线程
            return getExclusiveOwnerThread() == Thread.currentThread();
        }

        // Methods relayed to outer class

        final ConditionObject newCondition() {//独占锁可以获取等待队列
            return new ConditionObject();
        }

        final Thread getOwner() {//获取当前持有独占锁的线程
            return ((exclusiveCount(getState()) == 0) ?
                    null :
                    getExclusiveOwnerThread());
        }

        final int getReadLockCount() {//共享锁计数
            return sharedCount(getState());
        }

        final boolean isWriteLocked() {//独占锁是否被持有
            return exclusiveCount(getState()) != 0;
        }

        final int getWriteHoldCount() {//获取当前线程持有的写锁计数
            return isHeldExclusively() ? exclusiveCount(getState()) : 0;
        }

        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 == current.getId())
                return rh.count;

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

        /**
         * Reconstitute this lock instance from a stream
         * @param s the stream
         */
        private void readObject(java.io.ObjectInputStream s)
            throws java.io.IOException, ClassNotFoundException {
            s.defaultReadObject();
            readHolds = new ThreadLocalHoldCounter();
            setState(0); // reset to unlocked state
        }

        final int getCount() { return getState(); }//获取总读写状态
    }

NonfairSync

    static final class NonfairSync extends Sync {
        private static final long serialVersionUID = -8159625535654395037L;
        final boolean writerShouldBlock() {
            return false; // writers can always barge
        }
        final boolean readerShouldBlock() {
            /* As a heuristic to avoid indefinite writer starvation,
             * block if the thread that momentarily appears to be head
             * of queue, if one exists, is a waiting writer.  This is
             * only a probabilistic effect since a new reader will not
             * block if there is a waiting writer behind other enabled
             * readers that have not yet drained from the queue.
             */
            return apparentlyFirstQueuedIsExclusive();
        }
    }

    final boolean apparentlyFirstQueuedIsExclusive() {
        Node h, s;
        return (h = head) != null &&
            (s = h.next)  != null &&
            !s.isShared()         &&
            s.thread != null;
    }

FairSync

    static final class FairSync extends Sync {
        private static final long serialVersionUID = -2274990926593161451L;
        final boolean writerShouldBlock() {
            return hasQueuedPredecessors();
        }
        final boolean readerShouldBlock() {
            return hasQueuedPredecessors();
        }
    }

    public final boolean hasQueuedPredecessors() {
        // The correctness of this depends on head being initialized
        // before tail and on head.next being accurate if the current
        // thread is first in queue.
        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());
    }

使用方式

public class ReadWriteLockTest {

    private final Map<String, String> m = new TreeMap<String, String>();
    private final ReentrantReadWriteLock rwl = new ReentrantReadWriteLock();
    private final Lock r = rwl.readLock();
    private final Lock w = rwl.writeLock();

    public String get(String key) {
        r.lock();
        try {
            return m.get(key);
        } finally {
            r.unlock();
        }
    }

    public String put(String key, String value) {
        w.lock();
        try {
            return m.put(key, value);
        } finally {
            w.unlock();
        }
    }

    public void clear() {
        w.lock();
        try {
            m.clear();
        } finally {
            w.unlock();
        }
    }

}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值