ReentrantReadWriteLock

一、ReentrantReadWriteLock是什么?

ReentrantReadWriteLock采用读写分离的策略,允许多个线程可以同时获取读锁。
可以重入的读写锁,解决读多写少的情况,避免多线程下共享变量的争抢情况,提升执行效率。

规则: 读读兼容、 读写互斥

同一个线程可以拥有 writeLock 与 readLock (但必须先获取 writeLock 再获取 readLock, 反过来进行获取会导致死锁)

特点:

  • 支持公平和非公平的获取锁的方式;
  • 支持可重入,读线程在获取了读锁后还可以获取读锁;写线程在获取了写锁之后既可以再次获取写锁又可以获取读锁;
  • 允许从写入锁降级为读取锁,其实现方式是:先获取写入锁,然后获取读锁,最后释放写锁。但是,从读取锁升级为写入锁是不允许的;
  • 读取锁和写入锁都支持锁获取期间的中断;
  • Condition支持,仅写入锁提供了Condition实现,读取锁不支持Condition,readLock().newCondition()会抛出异常;

二、类结构组织&&构造函数

类结构组织
在这里插入图片描述

public interface ReadWriteLock {
    Lock readLock();
    Lock writeLock();
}

构造函数
默认为非公平锁,初始化ReadLock和WriteLock。

非公平锁执行效率高,可以减少上下文切换成本。

public ReentrantReadWriteLock(boolean fair) {
     sync = fair ? new FairSync() : new NonfairSync();
     readerLock = new ReadLock(this);
     writerLock = new WriteLock(this);
}

二、如何使用

private static final ReadWriteLock readWriteLock = new ReentrantReadWriteLock();

 	for (int i = 0; i < 3; i++) {
            threadPool.execute(() -> {
                try {
                    readWriteLock.writeLock().lockInterruptibly();
                    System.out.println("写入数据" + test);
                    TimeUnit.SECONDS.sleep(5);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } finally {
                    readWriteLock.writeLock().unlock();
                }
            });
	}

	for (int i = 0; i < 20; i++) {
            threadPool.execute(() -> {
                try {
                    readWriteLock.readLock().lockInterruptibly();
                    System.out.println("读取数据" + test);
                    TimeUnit.SECONDS.sleep(5);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } finally {
                    readWriteLock.readLock().unlock();
                }
            });
	}

三、核心概念源码认证

ReentrantReadWriteLock类结构说明

public class ReentrantReadWriteLock  implements ReadWriteLock, java.io.Serializable {

 	private final ReentrantReadWriteLock.ReadLock readerLock;//读锁
    private final ReentrantReadWriteLock.WriteLock writerLock;//写锁
    final Sync sync;//同步器

    abstract static class Sync extends AbstractQueuedSynchronizer {}//同步器
    //内部类  公平 和 非公平实现
    static final class FairSync extends Sync {}
    static final class NonfairSync extends Sync {}
     //内部类 读锁和写锁
	public static class WriteLock implements Lock, java.io.Serializable {}
	public static class ReadLock implements Lock, java.io.Serializable {}
}

核心同步器Sync

提供了公平和非公平锁的模板方法,内部有一个32位的state变量,我们这里切分高16位,低16位表示读锁和写锁的数量。

abstract static class Sync extends AbstractQueuedSynchronizer {

        static final int SHARED_SHIFT   = 16;//位数切割器
        static final int SHARED_UNIT    = (1 << SHARED_SHIFT);//高16位代表读锁
        static final int MAX_COUNT      = (1 << SHARED_SHIFT) - 1;//最大锁数量
        static final int EXCLUSIVE_MASK = (1 << SHARED_SHIFT) - 1;//低16位的锁数量&计算

        static int sharedCount(int c)    { return c >>> SHARED_SHIFT; }//获取目前持有读锁的线程数量
        static int exclusiveCount(int c) { return c & EXCLUSIVE_MASK; }//获取目前持有写锁的线程数量
        
        //高16位是读锁获取次数,这里可以获取当前线程重入锁的次数
 		static final class HoldCounter {
            int count = 0;
            // Use id, not reference, to avoid garbage retention
            final long tid = getThreadId(Thread.currentThread());
        }
        //继承ThreadLocal 初始化HoldCounter
        static final class ThreadLocalHoldCounter extends ThreadLocal<HoldCounter> {
            public HoldCounter initialValue() {
                return new HoldCounter();
            }
        }
        
		private transient ThreadLocalHoldCounter readHolds;//新建ThreadLocalHoldCounter 
        private transient HoldCounter cachedHoldCounter;//缓存最后一个线程获取读锁数量
 		private transient Thread firstReader = null;//保存第一个获取该读锁的线程
        private transient int firstReaderHoldCount;//保存第一个获取该锁读锁的线程,获取读锁的数量

        Sync() {
            readHolds = new ThreadLocalHoldCounter();//初始化ThreadLocalHoldCounter
            //使用volatile 保证可见性 readHolds 
            setState(getState()); // ensures visibility of readHolds
        } 
 }

公平锁和非公平锁

独占锁

公平锁非公平锁

writerShouldBlock() 这里查看队列是否有等待线程 公平锁和非公平的差距在这里

protected final boolean tryAcquire(int acquires) {
         
            Thread current = Thread.currentThread();获取当前线程
            int c = getState();获取State
            int w = exclusiveCount(c);计算独占锁的数量
            if (c != 0) {State锁数量不为0
                // (Note: if c != 0 and w == 0 then shared count != 0)
                if (w == 0 || current != getExclusiveOwnerThread())独占锁的数量是0 或 当前线程不是独占线程
                    return false; 返回false 进入等待队列
                if (w + exclusiveCount(acquires) > MAX_COUNT)计算独占线程是否大于最大线程数量限制
                    throw new Error("Maximum lock count exceeded");
                // Reentrant acquire
                setState(c + acquires);设置写锁数量
                return true;
            }
            if (writerShouldBlock() ||查看队列是否有等待线程  公平锁和非公平的差距在这里
                !compareAndSetState(c, c + acquires))或则CAS设置抢锁
                return false; 返回false 进入等待队列
            setExclusiveOwnerThread(current);获取到锁 设置自己独占
            return true;
        }
共享锁

公平锁非公平锁*

protected final int tryAcquireShared(int unused) {
          
            Thread current = Thread.currentThread();获取当前线程
            int c = getState();获取State
            if (exclusiveCount(c) != 0 && 独占线程是否不为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 = current;记录第一个写锁
                    firstReaderHoldCount = 1;
                } else if (firstReader == current) {如果同一个写锁
                    firstReaderHoldCount++; firstReaderHoldCount+1
                } 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;
            }
            return fullTryAcquireShared(current);
        }

构造方法

public interface ReadWriteLock {
    Lock readLock();//获取读锁
    Lock writeLock();//获取写锁
}
public class ReentrantReadWriteLock implements ReadWriteLock, java.io.Serializable {

	private final ReentrantReadWriteLock.ReadLock readerLock;//读锁
    private final ReentrantReadWriteLock.WriteLock writerLock;//写锁
    final Sync sync;//同步器
    
    public ReentrantReadWriteLock(boolean fair) {
        sync = fair ? new FairSync() : new NonfairSync();
        readerLock = new ReadLock(this);
        writerLock = new WriteLock(this);
    }
 }

核心内部类

Sync

AbstractQueuedSynchronizer 中有一个32位的state变量,我们这里切分高16位,低16位。

abstract static class Sync extends AbstractQueuedSynchronizer {

        static final int SHARED_SHIFT   = 16;//高16位表示读锁
        static final int SHARED_UNIT    = (1 << SHARED_SHIFT);//对高16位+1
        static final int MAX_COUNT      = (1 << SHARED_SHIFT) - 1;//最大锁数量
        //用于获取低16位的值0000 0000 0000 0000 1111 1111 1111  1111 
        static final int EXCLUSIVE_MASK = (1 << SHARED_SHIFT) - 1;

        static int sharedCount(int c)    { return c >>> SHARED_SHIFT; }//获取目前持有读锁的线程数量
        static int exclusiveCount(int c) { return c & EXCLUSIVE_MASK; }//获取目前持有写锁的线程数量
        
        //高16位是读锁获取次数,这里可以获取当前线程重入锁的次数
 		static final class HoldCounter {
            int count = 0;
            // Use id, not reference, to avoid garbage retention
            final long tid = getThreadId(Thread.currentThread());
        }
        //继承ThreadLocal 初始化HoldCounter
        static final class ThreadLocalHoldCounter extends ThreadLocal<HoldCounter> {
            public HoldCounter initialValue() {
                return new HoldCounter();
            }
        }
        
		private transient ThreadLocalHoldCounter readHolds;//新建ThreadLocalHoldCounter 
        private transient HoldCounter cachedHoldCounter;//缓存最后一个线程获取读锁数量
 		private transient Thread firstReader = null;//保存第一个获取该锁读锁的线程
        private transient int firstReaderHoldCount;//保存第一个获取该锁读锁的线程,获取读锁的数量

        Sync() {
            readHolds = new ThreadLocalHoldCounter();//初始化ThreadLocalHoldCounter
            //使用volatile 保证可见性
            setState(getState()); // ensures visibility of readHolds
        } 
 }

WriteLock

获取写锁

lock —》 acquire —》 tryAcquire

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();
            获取State
            int c = getState();
            计算写锁数量
            int w = exclusiveCount(c);
            状态值有效
            if (c != 0) {
                // (Note: if c != 0 and w == 0 then shared count != 0)
                写锁数量为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);设置写锁数量 写回State
                return true;
            }
            没有读锁 也没有写锁
            if (writerShouldBlock() ||
                !compareAndSetState(c, c + acquires))cas抢写锁
                return false;
            setExclusiveOwnerThread(current);成功
            return true;
        }

ReadLock

获取写锁

lock —》 acquireShared—》 tryAcquireShared

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();
            获取State
            int c = getState();
            获取写锁是否为0 并且 锁独占线程是不是当前线程
            if (exclusiveCount(c) != 0 &&
                getExclusiveOwnerThread() != current) 重入校验
                return -1;
             获取写锁数量  c >>> SHARED_SHIFT(16)
            int r = sharedCount(c);
            
            if (!readerShouldBlock() && 判断是否是公平锁
                r < MAX_COUNT &&  最大数量校验
                compareAndSetState(c, c + SHARED_UNIT)) {  cas加锁
                if (r == 0) { 读锁是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();获取当前线程的cachedHoldCounter 
                    else if (rh.count == 0)
                        readHolds.set(rh);
                    rh.count++;设置
                }
                return 1;
            }
            return fullTryAcquireShared(current);
 }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值