Java并发编程ReentrantReadWriteLock加读锁流程

 更新时间:2023年05月10日 11:10:42   作者:bright丶  
这篇文章主要介绍了Java并发编程ReentrantReadWriteLock加读锁流程,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪

正文

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的资料请关注脚本之家其它相关文章!

相关文章

  • 详解Java的文件与目录管理以及输入输出相关操作

    详解Java的文件与目录管理以及输入输出相关操作

    这篇文章主要介绍了详解Java的文件与目录管理以及输入输出相关操作,是Java入门学习中的基础知识,需要的朋友可以参考下
    2015-09-09
  • 使用多个servlet时Spring security需要指明路由匹配策略问题

    使用多个servlet时Spring security需要指明路由匹配策略问题

    这篇文章主要介绍了使用多个servlet时Spring security需要指明路由匹配策略问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2024-08-08
  • Java实现向数组里添加元素

    Java实现向数组里添加元素

    这篇文章主要介绍了Java实现向数组里添加元素方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2023-11-11
  • 浅谈idea中导入maven项目的两种方式

    浅谈idea中导入maven项目的两种方式

    本文主要介绍了浅谈idea中导入maven项目的两种方式,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2023-08-08
  • Java实现简易图书借阅系统

    Java实现简易图书借阅系统

    这篇文章主要为大家详细介绍了Java实现简易图书借阅系统,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2022-03-03
  • SpringBoot+微信小程序实现文件上传与下载功能详解

    SpringBoot+微信小程序实现文件上传与下载功能详解

    这篇文章主要为大家介绍了SpringBoot整合微信小程序实现文件上传与下载功能,文中的实现步骤讲解详细,快跟随小编一起学习一下吧
    2022-03-03
  • Java文件写入器FileWriter使用指南

    Java文件写入器FileWriter使用指南

    在Java中,FileWriter类用于将字符写入文件中,它继承了Writer类,因此可以使用Writer类中的所有方法,下面我们就来深入探讨一下FileWriter类的使用方法吧
    2023-10-10
  • Java实现单人信息管理程序

    Java实现单人信息管理程序

    这篇文章主要为大家详细介绍了Java实现单人信息管理程序,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2020-02-02
  • Spring security实现权限管理示例

    Spring security实现权限管理示例

    这篇文章主要介绍了Spring security实现权限管理示例,这里整理了详细的代码,具有一定的参考价值,感兴趣的小伙伴们可以参考一下。
    2017-01-01
  • @JsonSerialize不起作用的解决方案

    @JsonSerialize不起作用的解决方案

    这篇文章主要介绍了@JsonSerialize不起作用的解决方案,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2021-10-10

最新评论