Java并发Concurrent包的锁(四)——读写锁源码分析

本文详细分析了Java并发库Concurrent中的读写锁ReadWriteBarrierLock,探讨了ReadWriteLock接口的特性,它维护了读锁和写锁的独立访问。Read锁允许多个读线程并发,而Write锁是独占的。同时,文章对比了ReentrantReadWriteLock的NonfairSync和FairSync,解释了非公平模式与公平模式的区别。
摘要由CSDN通过智能技术生成

本文对读写锁源码进行了比较详细的分析。
另外可以参考可重入锁 ReentrantLock 的分析:Java并发Concurrent包的锁(三)——ReentrantLock源码分析

ReadWriteLock接口

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

public interface ReadWriteLock {
   
    // 获得读锁
    Lock readLock();
    // 获得写锁
    Lock writeLock();
}

与互斥锁相比,读-写锁允许对共享数据进行更高级别的并发访问。写线程虽然一次只有一个访问数据,但读线程可以同时读取,而在实际中,读取往往都是大量的,写入是偶尔的,读-写锁利用了这一点。从理论上讲,与互斥锁相比,使用读-写锁所允许的并发性增强将带来更大的性能提高。在实践中,只有在多处理器上并且只在访问模式适用于共享数据时,才能完全实现并发性增强。
如果数据不常修改,而主要用于搜索,适合使用读写锁;而如果数据更新十分频繁,数据大部分时间都被每个线程所独占,这种情况并发也提高不了太多效率。而且如果读取的操作用时太多,那么读写锁本身的开销就是最大的执行成本。所以具体问题还是要具体分析。

ReentrantReadWriteLock的Sync

读写锁引用了 Sync 类,和 ReentrantLock 的 Sync 一样是通过 AbstractQueuedSynchronizer 进行扩展的,下面对其代码进行分析:

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

        /*
         * 锁状态state是int型,读写分为两部分,各用一个无符号short来表示
         * 低位的表示写锁即独享锁,高位的表示读锁共享数
         */
        // 这个16是两个字节,一个short的长度
        static final int SHARED_SHIFT   = 16;
        // 1左移16位,为00000000 00000001 00000000 00000000
        static final int SHARED_UNIT    = (1 << SHARED_SHIFT);
        // 1左移16位,减1,为65535,读写的获取锁的最大次数
        static final int MAX_COUNT      = (1 << SHARED_SHIFT) - 1;
        static final int EXCLUSIVE_MASK = (1 << SHARED_SHIFT) - 1;

        // 右移16位,获取c高位的16位,表示读锁的共享总数(高位2字节全0)
        static int sharedCount(int c)    { return c >>> SHARED_SHIFT; }
        // 和两个字节的全1字节与操作,高位2字节全0,获取写锁的总数
        static int exclusiveCount(int c) { return c & EXCLUSIVE_MASK; }

        // 每个线程的计数器,保存读锁共享数
        static final class HoldCounter {
            int count = 0;
            final long tid = getThreadId(Thread.currentThread());
        }

        // ThreadLocal的子类
        static final class ThreadLocalHoldCounter
            extends ThreadLocal<HoldCounter> {
            // 初始化方法,返回HoldCounter
            public HoldCounter initialValue() {
                return new HoldCounter();
            }
        }

        // 读线程的一个集合,但不包括最后一个读线程和第一个读线程
        private transient ThreadLocalHoldCounter readHolds;
        // 最后一个读线程的计数
        private transient HoldCounter cachedHoldCounter;
        // 第一个读线程
        private transient Thread firstReader = null;
        // 第一个读线程的计数
        private transient int firstReaderHoldCount;

        Sync() {
            readHolds = new ThreadLocalHoldCounter();
            setState(getState()); // ensures visibility of readHolds
        }
        // 读锁的阻塞
        abstract boolean readerShouldBlock();

        // 写锁的阻塞
        abstract boolean writerShouldBlock();

        // 释放写锁
        protected final boolean tryRelease(int releases) {
            if (!isHeldExclusively())
                /
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值