Java并发编程ReentrantReadWriteLock加读锁流程

2023-05-30 0 4,944

目录

正文

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)) {
        if (r == 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();
            else if (rh.count == 0)
                readHolds.set(rh);
            rh.count++;
        }
        return 1;
    }
    return fullTryAcquireShared(current);
}

上面是尝试加读锁流程的代码,既然这篇是番外篇,那就不按正常流程一点一点去分析了,着重拿出一部分来分析一下。ReentrantReadWriteLockReentrantLock相比,除了多了读写锁之外,还增加了很多属性,比如firstReaderfirstReaderHoldCountcachedHoldCounter......那我们这篇文章就介绍一下这些新属性的含义以及上面代码中加锁成功后的处理。

属性介绍

static final class HoldCounter {
    int count = 0;
    final long tid = getThreadId(Thread.currentThread());
}

HoldCount类型用来存储线程ID和线程持有的读锁数量

private transient ThreadLocalHoldCounter readHolds;
static final class ThreadLocalHoldCounter
    extends ThreadLocal&lt;HoldCounter&gt; {
    public HoldCounter initialValue() {
        return new HoldCounter();
    }
}

readHolds通过ThreadLocal在线程本地存储了一个HoldCounter对象,表示当前线程持有的读锁重入数量,主要是为了方便在发生重入或者释放锁时,分别计算每个线程持有的读锁数量。

private transient HoldCounter cachedHoldCounter;

cachedHoldCounter存储的是最后一个获取读锁成功的线程持有的读锁数量。但是如果只有一个线程获取读锁,会使用firstReaderfirstReaderHoldCount来记录线程持有读锁数量,只有获取读锁的线程数大于1时才会用cachedHoldCounter存储最后线程持有的读锁数量。

private transient Thread firstReader = null;

第一个获取读锁的线程,确切地说是把读锁数量从0改成1的线程,并且当前还没有释放锁。如果第一个线程释放了锁,就会把firstReader设为null,只有当所有读锁释放之后,下一个获取读锁成功的线程就成为firstReader

private transient int firstReaderHoldCount;

第一个获取读锁的线程持有读锁的数量。

加锁成功处理

int r = sharedCount(c);
if (r == 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();
    else if (rh.count == 0)
        readHolds.set(rh);
    rh.count++;
}

这里截取加锁成功之后处理的代码来分析下对这些属性的操作。

  • if (r == 0)表示共享锁数量为0,当前线程就是第一个获取读锁成功的线程,所以firstReaderfirstReaderHoldCount记录的就是当前线程。
  • 如果读锁数量不是0,但是当前线程是第一个线程,那就直接在原来数量基础上进行累加 firstReaderHoldCount++;
  • 如果读锁数量不为0,而且当前线程也不是第一个线程,这时就需要用到cachedHoldCounter了。
    • rh == null表示当前线程是第二个线程,rh.tid != getThreadId(current)表示当前线程至少是第三个线程(这里不考虑重入情况,只考虑当前线程第一次获取读锁成功),两个条件合起来可以理解为之前缓存的最后一个获取读锁成功的线程不是当前线程,所以就需要更新为当前线程cachedHoldCounter = rh = readHolds.get()
    • 如果之前缓存的最后一个线程是当前线程,那么就会有一个特殊情况rh.count == 0,这里可以理解为一个线程释放了读锁之后又重新获取了读锁,释放完所有锁时,为了防止内存泄漏会调用readHolds.remove()清除线程本地存储的信息,而现在加锁成功了就需要在线程本地重新记录持有锁的数量,既然缓存的就是当前线程的,那就直接用缓存来更新到线程本地就可以了。

以上就是Java并发编程ReentrantReadWriteLock番外的详细内容,更多关于Java并发ReentrantReadWriteLock的资料请关注其它相关文章!

资源下载此资源下载价格为1小猪币,终身VIP免费,请先
由于本站资源来源于互联网,以研究交流为目的,所有仅供大家参考、学习,不存在任何商业目的与商业用途,如资源存在BUG以及其他任何问题,请自行解决,本站不提供技术服务! 由于资源为虚拟可复制性,下载后不予退积分和退款,谢谢您的支持!如遇到失效或错误的下载链接请联系客服QQ:442469558

:本文采用 知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议 进行许可, 转载请附上原文出处链接。
1、本站提供的源码不保证资源的完整性以及安全性,不附带任何技术服务!
2、本站提供的模板、软件工具等其他资源,均不包含技术服务,请大家谅解!
3、本站提供的资源仅供下载者参考学习,请勿用于任何商业用途,请24小时内删除!
4、如需商用,请购买正版,由于未及时购买正版发生的侵权行为,与本站无关。
5、本站部分资源存放于百度网盘或其他网盘中,请提前注册好百度网盘账号,下载安装百度网盘客户端或其他网盘客户端进行下载;
6、本站部分资源文件是经压缩后的,请下载后安装解压软件,推荐使用WinRAR和7-Zip解压软件。
7、如果本站提供的资源侵犯到了您的权益,请邮件联系: 442469558@qq.com 进行处理!

猪小侠源码-最新源码下载平台 Java教程 Java并发编程ReentrantReadWriteLock加读锁流程 https://www.20zxx.cn/763303/xuexijiaocheng/javajc.html

猪小侠源码,优质资源分享网

常见问题
  • 本站所有资源版权均属于原作者所有,均只能用于参考学习,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担
查看详情
  • 最常见的情况是下载不完整: 可对比下载完压缩包的与网盘上的容量,建议提前注册好百度网盘账号,使用百度网盘客户端下载
查看详情

相关文章

官方客服团队

为您解决烦忧 - 24小时在线 专业服务