ReentrantReadWriteLock

从源码中获得的体会

读锁的获取

		/**
         * tryAcquire
         * 获得state的值,看是否为0, 再获得w的值,也就是低16位写锁的值
         * state = 0,那么直接尝试去加锁,替换state,如果替换失败进队列,如果超出16位数的限制范围抛异常
         * state不为0,就看一下是不是当前有写锁不是这个线程或者有读锁,有就加锁失败进队列,再在同步队列里尝试去获得锁
         */
        lock.writeLock().lock();

        /**
         * 读锁,读锁本身是可重入的共享锁,可以被多个线程同时获取
         * 读锁的获取有三个判断条件:
         * 1. 不能被阻塞,也就是head队列后头不能有独占的节点或者公平锁就是后面不能有节点在等待
         * 2. 不能超出高16位的表示数限制
         * 3. CAS获取锁成功
         * 但是失败之后还会给它一次机会去fulltry一下,如果不是因为阻塞,等待队列里没东西,那么就可以继续CAS去获取!!!
         * 1. 如果其他线程有写锁并且不是自己,那么就直接退出返回失败
         * 2. 如果被阻塞了,这时候要判断一下重入了,threadlocal里面存的值就有用了,如果等于0说明不会发生重入,那么返回失败,不等于0就处理一下重入
         * 3. 有没有爆出高16位的表达范围,如果有那么退出
         * 4. 死循环CAS
         * 这其实也说明了,写锁会有更更高的优先级
         * 每个线程各自获取读锁的次数只能选择保存在本地的threadLocal里面
         * A充入3次,B重入1次,A的ThreadLocal保存了3,B的ThreadLocal保存了1 而读状态是3 + 1
         * tryAcquireShared
         *
         */
        lock.readLock().lock();
      /**
     * 读锁,读锁本身是可重入的共享锁,可以被多个线程同时获取
     * 读锁的获取有三个判断条件:
     * 1. 不能被阻塞,也就是head队列后头不能有独占的节点或者公平锁就是后面不能有节点在等待
     * 2. 不能超出高16位的表示数限制
     * 3. CAS获取锁成功
     * 但是失败之后还会给它一次机会去fulltry一下,如果不是因为阻塞,等待队列里没东西,那么就可以继续CAS去获取!!!
     * 1. 如果其他线程有写锁并且不是自己,那么就直接退出返回失败
     * 2. 如果被阻塞了,这时候要判断一下重入了,threadlocal里面存的值就有用了,如果等于0说明不会发生重入,那么返回失败,不等于0就处理一下重入
     * 3. 有没有爆出高16位的表达范围,如果有那么退出
     * 4. 死循环CAS
     * 这其实也说明了,写锁会有更更高的优先级

读锁的释放

protected final boolean tryReleaseShared(int unused) {
    Thread current = Thread.currentThread();
    if (firstReader == current) {
        if (firstReaderHoldCount == 1)
            // 如果等于 1,那么这次解锁后就不再持有锁了,把 firstReader 置为 null,给后来的线程用
            // 为什么不顺便设置 firstReaderHoldCount = 0?因为没必要,其他线程使用的时候自己会设值
            firstReader = null;
        else
            firstReaderHoldCount--;
    } else {
        // 判断 cachedHoldCounter 是否缓存的是当前线程,不是的话要到 ThreadLocal 中取
        HoldCounter rh = cachedHoldCounter;
        if (rh == null || rh.tid != getThreadId(current))
            rh = readHolds.get();

        int count = rh.count;
        if (count <= 1) {

            // 这一步将 ThreadLocal remove 掉,防止内存泄漏。因为已经不再持有读锁了
            readHolds.remove();

            if (count <= 0)
                throw unmatchedUnlockException();
        }
        // count 减 1
        --rh.count;
    }

    for (;;) {
        int c = getState();
        int nextc = c - SHARED_UNIT;
        if (compareAndSetState(c, nextc))
			//这里设置为0其实就是说明后面的节点可以来获得锁了,帮助写锁和读锁的获取
            return nextc == 0;
    }
}

写锁

写锁由于是独占的,和ReentrantLock比较相似,就不额外列出。
有个比较有意思的是writeShouldBlock方法,它在这的作用其实就是区分公平锁和非公平锁吧。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值