[JDK源码]J.U.C-AQS-ReentrantReadWriteLock

ReentrantReadWriteLock

读锁:就是用于读互斥区中保护的变量

写锁:就是用于写互斥区中保护的变量

读操作 是不需要上锁的,写需要上锁

适用于读多写少的场景,读锁可以并发,写锁与其他锁互斥。

主要属性和构造器

public class ReentrantReadWriteLock implements ReadWriteLock {
    // 读锁对象
    private final ReentrantReadWriteLock.ReadLock readerLock;
    // 写锁对象
    private final ReentrantReadWriteLock.WriteLock writerLock;
    // 同步器
    final Sync sync;
    // 默认构造器创建了非公平锁
    public ReentrantReadWriteLock() {
        this(false);
    }
    // 根据fair变量,来选择创建不同的锁:公平锁 FairSync 和非公平锁 NonfairSync
    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 interface ReadWriteLock {
    // 用于获取读锁
    Lock readLock();
    // 用于获取写锁
    Lock writeLock();
}

内部类

abstract static class Sync extends AbstractQueuedSynchronizer {}
static final class NonfairSync extends Sync {}
static final class FairSync extends Sync {}
public static class ReadLock implements Lock, java.io.Serializable{}
public static class WriteLock implements Lock, java.io.Serializable {}

FairSync

公平锁

final boolean writerShouldBlock() {
    return hasQueuedPredecessors();
}
final boolean readerShouldBlock() {
    return hasQueuedPredecessors();
}

hasQueuedPredecessors() 方法,就是看AQS的阻塞队列里是否有其他线程在等待,如果有就去排队。

NofairSync

非公平锁

final boolean writerShouldBlock() {
    return false; // 写线程拥有是false
}
final boolean readerShouldBlock() {
    return apparentlyFirstQueuedIsExclusive();
}

读线程 apparentlyFirstQueuedIsExclusive()方法,不应该让写线程饥饿,非公平,不管前面是否有人排队都去抢。

有写锁在排队的抢矿下 去排队 : R->W->R

sync类

读锁可以多个线程同时持有,写锁只允许一个线程持有,读锁(共享锁)写锁(互斥锁),AQS中state变量分割为 高16位低16位,高16位表示读锁,低16位表示写锁

abstract static class Sync extends AbstractQueuedSynchronizer {
    //简单的位运算
    static final int SHARED_SHIFT   = 16; //高16位表示读锁
    static final int SHARED_UNIT    = (1 << SHARED_SHIFT);
    //最大读锁数量
    static final int MAX_COUNT      = (1 << SHARED_SHIFT) - 1;
    //左移16位 -1  后16位 1
    static final int EXCLUSIVE_MASK = (1 << SHARED_SHIFT) - 1;
    /** 获取 shared 共享锁 读锁 的线程数量*/
    static int sharedCount(int c)    { return c >>> SHARED_SHIFT; }
    /** 获取 exclusive 排他 写锁 的线程数量 */
    static int exclusiveCount(int c) { return c & EXCLUSIVE_MASK; }

   /*** 用于每个线程读取保持计数的计数器。 维护为ThreadLocal; 缓存在cachedHoldCounter */
   static final class HoldCounter {
        int count = 0;
       final long tid = getThreadId(Thread.currentThread());
   }
    //继承ThreadLocal  重写initialValue 方法,调用时初始化 HoldCounter计数器
   static final class ThreadLocalHoldCounter
        extends ThreadLocal<HoldCounter> {
        public HoldCounter initialValue() {
            return new HoldCounter();
        }
   } 
    //ThreadLocal 对象
   private transient ThreadLocalHoldCounter readHolds;
	//最后一个要成功获取的线程的持有计数  
   private transient HoldCounter cachedHoldCounter;
	//保存了 第一个读线程
   private transient Thread firstReader = null;
    //保存此锁线程获取到第一个的读多数量
   private transient int firstReaderHoldCount;
   Sync() {
       //初始化 
       readHolds = new ThreadLocalHoldCounter();
       // 确保readhold的可见性
       setState(getState()); 
   }     
}

tryAcquire方法

//写锁的获取流程
protected final boolean tryAcquire(int acquires) {
	//获取当前线程
    Thread current = Thread.currentThread();
    //c 获取当前状态
    int c = getState();
    //互斥锁数量
    int w = exclusiveCount(c);
    if (c != 0) {
        //当前不是写锁 或者 当前线程不是写锁
        if (w == 0 || current != getExclusiveOwnerThread())
            return false;
        //写锁 重入  写锁保存在低16位
        if (w + exclusiveCount(acquires) > MAX_COUNT)
            throw new Error("Maximum lock count exceeded");
        // Reentrant acquire
        setState(c + acquires);
        return true;
    }
    // 当前线程是否应该获取写锁,CAS抢锁
    if (writerShouldBlock() ||
        !compareAndSetState(c, c + acquires))
        return false;
    //获取写锁成功 将当前线程标位 获取写锁的线程对象
    setExclusiveOwnerThread(current);
    return true;
}

tryRelase

//释放写锁
protected final boolean tryRelease(int releases) {
    if (!isHeldExclusively())//没有获取到写锁
        throw new IllegalMonitorStateException();
     // 释放完毕后,写锁状态是否为0(锁重入),因为此时计算的不是当前state,是nextc 
    int nextc = getState() - releases;
    boolean free = exclusiveCount(nextc) == 0;
    if (free)
        setExclusiveOwnerThread(null);
    //设置 state变量
    setState(nextc);
    //返回 true 的情况下,有AQS来完成后续唤醒操作
    return free;
}

tryAcquireShared、fullTryAcquireShared方法

//tryAcquireShared获取读锁的流程获取写锁的流程
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 增加高16位的读锁数量
        if (r == 0) {
            firstReader = current;
            firstReaderHoldCount = 1;
        } else if (firstReader == current) {
            //当前获取读锁的线程是一个线程 锁重入 
            firstReaderHoldCount++;
        } else {
            //当前不是第一个读线程,将获取读锁的次数保存在ThreadLocal中
            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);
}
final int fullTryAcquireShared(Thread current) {
    HoldCounter rh = null;
    for (;;) {
        int c = getState();
        if (exclusiveCount(c) != 0) {//有写锁, 当前获取到的写锁线程不是,当前线程
            if (getExclusiveOwnerThread() != current)
                return -1;
        } else if (readerShouldBlock()) {//是否需要阻塞
            // 当前线程是第一个获取到的 读锁线程
            if (firstReader == current) {
            } else {//获取当前线程记录读锁重入次数的  HoldCounter 对象
                if (rh == null) {
                    rh = cachedHoldCounter;
                    if (rh == null || rh.tid != getThreadId(current)) {
                        rh = readHolds.get();
                        if (rh.count == 0)
                            readHolds.remove();
                    }
                }
                if (rh.count == 0)//当前读锁 重入次数为0,表示没有获取锁 返回-1
                    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) {//下边这些操作 和 trAcquire 方法中 一样
                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;
        }
    }
}

tryReleaseShared释放读锁

protected final boolean tryReleaseShared(int unused) {
    Thread current = Thread.currentThread();
    if (firstReader == current) {//当前线程是第一个获取到读锁的线程
        if (firstReaderHoldCount == 1)//当前重入次数为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) {//当前线程释放之后 ThreadLocal里不需要它了
            readHolds.remove();
            if (count <= 0)
                throw unmatchedUnlockException();
        }
        --rh.count;
    }
    for (;;) {//CAS 释放高16位
        int c = getState();
        int nextc = c - SHARED_UNIT;
        if (compareAndSetState(c, nextc))
            return nextc == 0;//为0的情况下为无锁状态,由AQS来唤醒
    }
}

一个state分为高16低16,高表示读,低表示写,在进行写时,保证写线程不饥饿有没有写锁 有写锁去排队,默认是非公平的。

  • 19
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 18
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值