Java并发(十二):读写锁——读锁

多线程之读写锁原理 今天主要通过多读单写的例子来说下读写锁的原理 概念 多读单写,简单说,就是对资源的访问分为两种状态,一种是读操作,另一种是写操作。由应用程序提示锁应该做哪种操作。当为读模式时,所有的写动作被悬挂,而读请求被允许通过,而写动作时,所有操作被悬挂。并且,读写切换时,有足够的状态等待,直到真正安全时,才会切换动作。 如下图所示: 业务场景举例 比如现在有 A、B、C、D、E、F、G 6个线程,其中A、B、C、G 4个线程之行读请求,E、F 2个线程之行写请求,如何保证读写安全? 分析: .. 阅读详情

回顾

前面我们已经看了写锁是怎样进行获取和释放的,下面就来看看读锁的获取和释放

读锁

写锁是一个排他锁,而读锁却是一个共享锁,而且还支持可重入,并且能被多个线程同时获取

读锁的获取

在这里插入图片描述
在这里插入图片描述
可以看到,其底层的实现也是AQS,只不过是AQS的共享模式,并且执行的是AQS的acquireShared方法

源码如下

    public final void acquireShared(int arg) {
        //执行tryAcquireShared方法尝试进行获取共享锁
        if (tryAcquireShared(arg) < 0)
            //获取共享锁失败,进行CAS自旋(写锁被获取了)
            doAcquireShared(arg);
    }

可以看到获取共享锁的主要方法为tryAcquireShared

tryAcquireShared

源码如下

        protected final int tryAcquireShared(int unused) {
            /*
             * Walkthrough:
             * 1. If write lock held by another thread, fail.
             * 2. Otherwise, this thread is eligible for
             *    lock wrt state, so ask if it should block
             *    because of queue policy. If not, try
             *    to grant by CASing state and updating count.
             *    Note that step does not check for reentrant
             *    acquires, which is postponed to full version
             *    to avoid having to check hold count in
             *    the more typical non-reentrant case.
             * 3. If step 2 fails either because thread
             *    apparently not eligible or CAS fails or count
             *    saturated, chain to version with full retry loop.
             */
            //依然从注释上开始看起,注释同样提到了三点
            //1.如果其他线程拥有了写锁,获取共享锁失败
            //2.如果没有写锁,就代表可以获取共享锁,不过要现判断是否应该进行阻塞(由于队列策略)
            //	并且通过CAS的方法更新同步状态,更新成功就代表获取锁成功
            //3.如果获取共享锁失败,代表CAS失败或者共享锁数量满了
            
            //获取当前线程
            Thread current = Thread.currentThread();
            //获取当前同步状态量
            int c = getState();
            //获取低位,也就是获取写锁的同步状态量
            //判断写锁的同步状态量是否为0,即有没有线程去获取写锁
            //如果写锁被人获取了,再判断写锁的拥有者是不是当前线程
            //因为规定拥有写锁的线程可以去拥有读锁
            if (exclusiveCount(c) != 0 &&
                getExclusiveOwnerThread() != current)
                //如果写锁被获取了,且写锁不是被自己获取
                //获取共享锁失败,返回-1
                return -1;
            //获取共享锁的同步状态量
            int r = sharedCount(c);
            //判断获取共享锁需要不需要进行阻塞
            //判断共享锁的同步状态量是不是达到了最大值
            //判断CAS改变共享锁的同步状态量是否成功
            if (!readerShouldBlock() &&
                r < MAX_COUNT &&
                compareAndSetState(c, c + SHARED_UNIT)) {
                //如果共享锁的同步状态量为0,证明是第一个去获取共享锁
                //注意此时这里会有并发问题
                //假如第一个线程在CAS这里停止了,那么后面线程获取的同步状态量依然为0
                if (r == 0) {
                    //将第一个获取共享锁的线程设置为当前线程
                    //这里是有并发问题的
                    firstReader = current;
                    //记录第一个线程获取共享锁的次数
                    firstReaderHoldCount = 1;
                } else if (firstReader == current) {
                    //如果第一个获取共享锁的线程,又去获取共享锁
                    //次数+1,代表重入了
                    firstReaderHoldCount++;
                } else {
                    //如果是其他线程进来获取共享锁
                    //定义一个HoldCounter缓存
                    HoldCounter rh = cachedHoldCounter;
                    //HoldCounter缓存存储在ThreadLocalMap中
                    if (rh == null || rh.tid != getThreadId(current))
                        //如果缓存为空,代表第一次其他线程进来
                        //如果缓存不为空,但此时的缓存不属于当前线程(线程ID不对应)
                        //从ThreadLocal的ThreadLocalMap中去取当前线程的缓存
                        cachedHoldCounter = rh = readHolds.get();
                    else if (rh.count == 0)
                        //如果缓存中的count为0
                        //将缓存添加进容器中
                        readHolds.set(rh);
                    //通过holdCounter记录其他线程获取的共享锁次数
                    rh.count++;
                }
                //返回1,代表加锁成功
                return 1;
            }
            //如果CAS失败或其他原因导致失败
            //调用fullTryAcquireShared方法
            //其实里面底层是
            return fullTryAcquireShared(current);
        }

从代码上可以看到,共享锁其实还挺复杂

  • 判断写锁有没有被线程获取

    • 如果写锁被获取了,再判断写锁是不是被当前线程获取,如果是当前线程获取,仍然可以继续去获取读锁
    • 如果写锁被获取了,且并不是当前线程获取的,直接reutnr -1,代表获取读锁失败
  • 判断是否需要进行阻塞

  • 判断读锁的同步状态量是否达到最大值

  • 判断CAS更换读锁的同步状态量是否成功

  • 只有满足上面三个判断,才代表获取锁成功

  • 获取锁成功之后就要进行记录重入次数了,虽然我们更改了读锁的同步状态量,但读锁的同步状态量是一个整体的,而读锁是共享的,即每个线程都有,所以需要每个线程去记录读锁的重入次数

    • 对于第一个获取共享锁的线程,进行记录,并且记录其重入次数
    • 对于其他线程,是使用ThreadLocal来进行存储的,具体的底层容器为ThreadLocalMap
  • 如果获取锁失败,会调用fullTryAcquireShared方法,这个方法的本质上是CAS进行tryAcquiredShared。。。

前面的步骤都还好理解,重点在于读锁怎么去存储各个线程的重入次数的

记录各个线程的重入次数

对于被firstReader记录的线程还好说,通过firstReaderHoldCount进行记录即可

但对于其他线程,则是利用ThreadLocalMap来进行存储的

HoldCounter

每个线程对应的缓存其实就是一个HoldCounter

在这里插入图片描述
可以看到,这个类里面有两个属性

  • count:记录重入次数
  • tid:记录线程ID

从前面可以看到,当前缓存为空,或者该缓存并不属于当前线程(线程ID不对应),那么就会走readHolds的get方法

从判断条件可以看到,这个get方法应该会做两种事情

  • 缓存为空,证明没创建,需要进行初始化
  • 缓存不属于当前线程,需要进行切换线程

在这里插入图片描述
在这里插入图片描述
从源码中可以看到,readHolds本质上是一个ThreadLocalHoldCounter对象,并且继承了ThreadLocal,并且泛型是HoldCounter,所以ThreadLocalHoldCounter拥有ThreadLocal的功能,而ThreadLocal有存储功能,可以将元素存储在ThreadLocalMap中

下面就来看看get方法是做什么的

readHolds.get

在这里插入图片描述
可以看到,这个方法来自ThreadLocal源码如下

    public T get() {
        //获取当前线程
        Thread t = Thread.currentThread();
        //获取ThreadLocalMap
        ThreadLocalMap map = getMap(t);
        //如果ThreadLocalMap不为空
        if (map != null) {
            //根据当前ThreadLocal去获取存储的键值对
            ThreadLocalMap.Entry e = map.getEntry(this);
            if (e != null) {
                //如果键值对不为空,返回value
                @SuppressWarnings("unchecked")
                T result = (T)e.value;
                return result;
            }
        }
        //如果ThreadLocalMap为空,需要进行初始化
        return setInitialValue();
    }

从这里大概就可以看到大致的模型了

当前线程的ThreadLocalMap中存储了以ThreadLocalHoldCounter的父类ThreadLocal为键的,HoldCounter为值的键值对,键是每个线程都能拿到的,但这里能进行区分是因为每个线程都存在了自己的ThreadLocalMap中,这样就进行区分了

在这里插入图片描述
在这里插入图片描述
可以看到,其底层其实是一个Entry数组

setInitialValue方法

这个方法其实就是当ThreadLocalMap没有创建的时候,需要进行初始化的时候调用

    */
    private T setInitialValue() {
        //获取默认值
        //默认值为null
        T value = initialValue();
        //获取当前线程
        Thread t = Thread.currentThread();
        //再次判断有没有创建
        ThreadLocalMap map = getMap(t);
        if (map != null)
            //如果已经创建,直接set方法改变里面的entry属性
            map.set(this, value);
        else
            //如果没创建,就进行创建
            createMap(t, value);
        return value;
    }

在这里插入图片描述

set方法

当count属性为0时,会调用set方法,这个方法其实是用来修改值的或者为空时进行初始化的,没太看懂这个是干嘛的。。是为0时还没有进入缓存吗?

在这里插入图片描述
最后初始化缓存和容器了之后,就进行对缓存的count属性进行自增1了,这样就对应记录了每个线程的重入次数了

假如第一次获取失败

第一次获取失败是会执行fullTryAcquireShared方法的,这个方法名也挺有讲究,翻译为完全尝试,前面先尝试,尝试失败就进行完全尝试

源码如下

        final int fullTryAcquireShared(Thread current) {
            /*
             * This code is in part redundant with that in
             * tryAcquireShared but is simpler overall by not
             * complicating tryAcquireShared with interactions between
             * retries and lazily reading hold counts.
             */
            HoldCounter rh = null;
            //死循环
            //已经在开始自旋获取锁了
            for (;;) {
                //获取锁的状态量
                int c = getState();
                //获取写锁的状态量
                if (exclusiveCount(c) != 0) {
                    //并且判断,如果有人获取了写锁,并且该写锁的拥有者不是自己,返回-1
                	//交由AQS去实现共享锁了
                    if (getExclusiveOwnerThread() != current)
                        return -1;
                    // else we hold the exclusive lock; blocking here
                    // would cause deadlock.
                }
                //如果没人获取写锁,或者写锁的拥有者是自己
                //判断获取读锁需不需要进行阻塞
                //这个方法对于公平锁和非公平锁有不同实现
                //为什么要判断要阻塞了,这就涉及到公平与非公平的性质
                //公平的话,肯定是要进行排队的,非公平的话不需要进行排队
                else if (readerShouldBlock()) {
                    // Make sure we're not acquiring read lock reentrantly
                    //如果进来需要进行阻塞,也就意味着需要进行排队,即前面已经有线程等待了
                    //这里是保证当前线程没有以可重入的方式获取锁的
                    //因为如果是以可重入的方式去获取锁,那就没有什么插不插队的概念了
                    //就比如买票看电影一样,你已经排队买了电影票了,然后有事离开了一下,那么下一次进来还需要排队买票吗?
                    //判断firstReader是不是当前线程,如果是就不用清除了
                    //因为第一个获取读锁的线程由ReentrantReadWriteLock维护
                    if (firstReader == current) {
                        //并且如果是第一个线程获取的,那就代表发生可重入了,没有插队概念
                        //不做任何处理,继续获取锁
                        // assert firstReaderHoldCount > 0;
                    } else {
                        //如果第一个获取读锁的线程不是自己,那就代表有其他线程已经拿到锁了
                        //下面就需要进行判断,当前线程获取读锁需不需要进行排队
                        if (rh == null) {
                            //获取缓存,即前一次获取锁的线程
                            rh = cachedHoldCounter;
                            //如果为空或者缓存的线程ID不为自己
                            //代表了
                            if (rh == null || rh.tid != getThreadId(current)) {
                                //获取自己ThreadLocal存储的共享锁状态量
                                rh = readHolds.get();
                                //如果为0.清空掉
                                if (rh.count == 0)
                                    //清空掉当前线程的ThreadLocal的读锁状态量
                                    readHolds.remove();
                            }
                        }
                        //为什么此时rh.count仍然为0就return????
                        //因为进入到这里代表了线程需要进行阻塞,而阻塞是交由AQS决定的
                        //如果是第一次获取锁,就代表没有发生可重入,那就需要进行排队了
                        //返回-1,让AQS去实现阻塞排队
                        if (rh.count == 0)
                            return -1;
                    }
                }
                //判断现在读锁的状态量是不是已经为最大值了
                if (sharedCount(c) == MAX_COUNT)
                    //如果为最大值,代表读锁的数量已经满了,不能获取了,抛出异常
                    throw new Error("Maximum lock count exceeded");
                //如果没满最大值,那就进行CAS替换状态量
                if (compareAndSetState(c, c + SHARED_UNIT)) {
                    //替换成功就进行获取锁
                    //上面已经分析过,这里不再赘述
                    if (sharedCount(c) == 0) {
                        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
                    return 1;
                }
                //获取锁失败,就进行下一轮循环
            }
        }

可以看到,这个方法其实是在CAS获取读锁的基础上,添加了阻塞功能,也就是说完整的尝试获取锁,不仅是判断写锁的状态和读锁的状态,还需要去考虑是否要阻塞

而考虑这个阻塞问题,其实就是关于公平锁和非公平锁的判断了,这里要注意一点的就是可重入锁是没有排队这个概念的!!!!

【目标检测】全局上下文感知的详解 目标检测中的全局上下文感知(Global Context Awareness)​是指模型在定位和识别目标时,能够有效利用图像中全局或大范围的上下文信息(如场景语义、目标间关系、空间布局等),而不仅仅依赖局部特征。这种能力显著提升了检测的鲁棒性,尤其是在复杂场景(如遮挡、小目标、密集目标)中表现突出。 阅读详情

相关推荐

头歌操作系统 课堂练习4.2:页式内存管理 答案 无解析

头歌操作系统 课堂练习4.2:页式内存管理 答案 无解析

kercii的博客 1万+

ReentrantReadWriteLock分析

ReentrantReadWriteLock分析 依然使用state变量表示锁的获取状态,因为读写锁涉及读锁和写锁,因此用state变量的高16位和低16位作为区分,分别代表读锁的获取次数,以及写锁的重入次数。 1、写锁加锁过程 protected final boolean tryAcquire(int acquires) { // 当前获取锁的线程 Thread current = Thread.currentThread(); //

博客 216

在ubuntu20.04上配置VINS_Fusion(亲测有效,一应俱全)

最近在做科研训练的时候配置了HKUST-Aerial-Robotics实验室的VINS_Fusion代码项目,经历了一些编译报错的问题,在网上查找的时候博客内容良莠不齐,且实质针对性意见不多,于是在此记录下自己配置期间遇到的一些共性问题,留作自己日后参考和大家的交流学习。

wyr1849089774的博客 8268

java read write lock_理解ReentrantReadWriteLock可重入读-写锁(转)

abstractbooleanreaderShouldBlock();abstractbooleanwriterShouldBlock();写锁的tryXXX获取和释放1.写锁释放时,由于没有其他线程获得临界区,它的tryRelease()方法只需要设置状态的值,通过exclusiveCount计算写锁的计数器,如果为0表示释放了写锁,就把exclusiveOwnerThread设置为null.2...

weixin_31485835的博客 205

GIS分析-利用K-Means方法进行地震分析

通过“聚类”可以获得有关我们所拥有的数据的各种线索,这是数据挖掘技术之一。分析创建的组有助于决策过程。在这项研究中,我们将使用数据挖掘工具之一的K-Means方法研究安纳托利亚东部地区近100年发生的地震的空间分布,并试图获得有用的信息,以供未来的研究使用。我从局地震目录页面获得了研究所需的地震数据,并从获得了区域边界数据。

gis收藏家的博客 1570

Qwen-Image-2512 本地部署完全指南:从零开始搭建你的AI绘图工作站

阿里通义团队开源了Qwen-Image-2512模型,这款AI绘图模型在人物真实感、自然细节和文字渲染上表现惊艳,甚至在盲测中超越部分闭源模型。本文提供了详细的本地部署教程,从硬件准备、环境安装到使用ComfyUI运行模型,手把手教你生成第一张AI图片,并分享了进阶技巧和免费在线体验方式。

莫潇羽的个人博客 2426

ReentrantReadWriteLock原理分析

待更新

weixin_44399827的博客 250

告别Keil手动分区!用CubeMX+VS Code一键生成带Bootloader的STM32 OTA工程

本文详细介绍了如何利用STM32CubeMX和VS Code实现STM32 OTA工程的自动化构建,告别传统Keil手动分区的繁琐流程。通过图形化配置Flash分区、自动生成链接脚本以及实现Bootloader跳转逻辑,开发者可以高效完成远程升级功能开发,显著提升嵌入式开发效率。

weixin_33720956的博客 389

【基本功】不可不说的Java“锁”事

总第303篇2018年 第95篇并发编程是Java程序员必备基本功,今天“基本功”专栏向大家推荐一篇深入解析Java锁机制的文章。Enjoy!前言Java提供了种类丰富的...

美团技术团队 4217

【定位教程2----旋转中心标定之方法一】

【定位教程2----旋转中心标定之方法一】

Quintin 3万+

pytorch 51 GroundingDINO模型导出tensorrt并使用c++进行部署,53ms一张图

博主基于https://github.com/hpc203/GroundingDINO-onnxrun项目分享的onnx c++推理代码,修改为GroundingDINO模型的tensorrt推理代码。对于600x400的输入,在3060显卡下,cuda 12.1,TensorRT-10.4.0,window环境下53ms处理完一张图片。

a486259的博客 1221

[并发进阶]——读写锁 原理

通过图解流程以及阅读源码的方式带你深入理解读写锁,让你真正理解其原理

热爱编程的机械生的救赎 1952

PNETLab 镜像包官方下载太慢?不急,最新版本PNET_4.2.10分享!

你好,这里是网络技术联盟站,我是瑞哥。PNETLab是一个强大的网络仿真工具平台,全称Packet Network Emulator Tool Lab。它不仅允许用户进行深入的网络实验,还支持社区成员之间的实验室共享。PNETLab致力于为学习者、教师以及网络工程师提供一个全面的实验环境,以便于他们能够在实际部署前测试和验证网络配置和协议。和。这两个部分相辅相成,共同构成了一个全面且灵活的网络仿真生态系统。

网络技术联盟站 4472

图文深入解析 JAVA 读写锁,为什么读锁套写锁会死锁,反过来却不会?

一、回顾基本的读写锁 我们知道读写锁 #java.util.concurrent.locks.ReentrantReadWriteLock 是一个 “读写互斥,写写互斥,读读共享” 的锁。 读写锁的使用非常简单,那就是: 我们只需要保证读锁和写锁来自同一个 ReentrantReadWrit...

chongshizhuo8736的博客 2631

IDEA的使用指南

IDEA基于java的使用手册,可以最快速的上手,在使用中不断的丰富自己的使用技巧.

OV9734 DATASHEET,完整规格书

OV9734完整规格书,包括电气参数,尺寸规格,寄存器配置表等

33.Java读写锁(认识读写锁、读写锁案例、锁降级、锁的演变)

33.Java读写锁(认识读写锁、读写锁案例、锁降级、锁的演变)

weixin_52173250的博客 1569

lwip-2.0.3

lwip是瑞典计算机科学院(SICS)的Adam Dunkels 开发的一个小型开源的TCP/IP协议栈。实现的重点是在保持TCP协议主要功能的基础上减少对RAM 的占用。

Java并发编程--12-读写锁与StampedLock:高并发读场景下的性能优化利器

本文深入分析了Java并发编程中读写锁与StampedLock的应用场景与技术原理。针对读多写少的高并发场景,传统独占锁会导致性能瓶颈,而读写锁通过"读读共享、读写互斥"机制显著提升并发度。文章详细解读了ReentrantReadWriteLock的核心设计、锁降级实现及写饥饿问题,并对比了JDK8引入的StampedLock创新性"乐观读"模式。通过性能测试数据、代码示例和架构图,系统性地阐述了两种锁的适用场景、实现原理和最佳实践,为开发者在高并发系统优化中提供了关

weisian的博客 7288

精雕软件(JDpaint) 5.5 绿色版

精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版

并发编程:读写锁

本文主要介绍并发编程中读写锁的知识

AWSDN的博客 1145

Java并发之-读写锁ReentrantReadWriteLock

前言 之前提到的ReentrantLock是排他锁,这种锁同一时刻只允许一个线程访问,而读写锁同一时刻可以多个线程访问,但在写线程访问时,所有读线程和其他写线程都要被阻塞。读写锁维护了一对锁,一个读锁和一个写锁,通过分离读写锁,使得并发性相比一般的排他锁有很大提升。 参考文献 《Java并发编程的艺术》 正文 读写锁只需要在读操作时获取读锁,写操作获取写锁即可。当写操作被获取时,后续读写...

晏霖/胖虎的博客 4679

java写多读少用什么锁_Java 读写锁 原来这么简单

Java ReentranReadWriteLock前言一、技术介绍1.ReentranReadWriteLock是什么?二、源码分析1.ReadLock2.WriteLock三、单元测试总结作者寄语提示:下方有源代码地址,请自行拿取前言在实际项目中,比如我们有一个共享资源文件,我们程序会会同时并发的去读、写这个共享资源文件,那怎么能保证在高并发场景下安全、高效读写呢?OK,看了下文便知提示:以下...

weixin_29962351的博客 1333

33、java读锁应该插队吗?以及什么是读写锁的升降级

对于 ReentrantReadWriteLock 而言。插队策略公平策略下,只要队列里有线程已经在排队,就不允许插队。非公平策略下:如果允许读锁插队,那么由于读锁可以同时被多个线程持有,所以可能造成源源不断的后面的线程一直插队成功,导致读锁一直不能完全释放,从而导致写锁一直等待,为了防止“饥饿”,在等待队列的头结点是尝试获取写锁的线程的时候,不允许读锁插队。

zht245648124的博客 1064

Java中的锁——ReentrantReadWriteLock(读写锁)

上一篇里讲的ReentrankLock是一种排他锁,即同一时间只能有一个线程进入。而读写锁在同一时刻允许多个读线程访问,但是在写线程访问时,所有的读线程和其他线程均被阻塞。读写锁维护了一对锁,一个读锁和一个写锁,通过分离读写锁,使得并发性比一般的排它锁有了很大提升。因为大多数应用场景都是读多于写的,因此在这样的情况下,读写锁可以提高吞吐量。下图描述了关于读写锁的三个特性:公平性、重入性和锁降级。

惟愿无事 3258

java 读锁有什么用_什么是读写锁

我们知道多个线程同时读一个资源类是没有任何问题的,所以在并发的情况下,读取共享资源应该是可以同时进行的;但是,如果一个线程想要去写共享资源,就不应该再有其他线程同时对该共享资源进行读或者是写操作了。我们想要的是:允许多个线程同时读,但只要有一个线程在写,其他线程就必须等待。读写锁就是这个原理,即读写锁在同一时刻可以允许多个多线程访问,但是在写线程访问的时候,所有的读线程和其他写线程都会被阻塞。读写...

weixin_35693055的博客 897

java并发锁ReentrantReadWriteLock读写锁源码分析

1、ReentrantReadWriterLock 基础 所谓读写锁,是对访问资源共享锁和排斥锁,一般的重入性语义为如果对资源加了写锁,其他线程无法再获得写锁与读锁,但是持有写锁的线程,可以对资源加读锁(锁降级);如果一个线程对资源加了读锁,其他线程可以继续加读锁。 java.util.concurrent.locks中关于多写锁的接口:ReadWriteLock。 public inte...

中间件兴趣圈 2万+

java并发之ReentrantReadWriteLock的读锁

ReentrantReadWriteLock是juc包下的一个锁工具类,可以同时获取读锁和写锁,读锁底层为共享锁,写锁底层为独占锁.读锁可以重复获取,写锁只可以有一个线程获取,并且读写锁互斥.读锁不可以升级为写锁.而写锁可以降级为读锁.是为了保证多线程情况下数据的可见性.

不愿言弃-念何的博客 674

java线程之读写锁

一、什么是读写锁 读写锁是JDK1.5提供的一个工具锁,适用于读多写少的场景,将读写分离,从而提高并发性。 二、读写锁的特点 读锁是共享锁,写锁是排他锁,读锁和写锁不能同时存在; 读锁不能升级为写锁; 写锁可以降级为读锁; 三、代码演示 import java.util.HashMap; import java.util.Map; import java.util.concurrent.TimeUnit; import java.util.concurrent.locks.Lo

一起coding,一起嗨。 7525

并发锁之二:ReentrantReadWriteLock读写锁

一、简介   读写锁是一种特殊的自旋锁,它把对共享资源对访问者划分成了读者和写者,读者只对共享资源进行访问,写者则是对共享资源进行写操作。读写锁在ReentrantLock上进行了拓展使得该锁更适合读操作远远大于写操作对场景。一个读写锁同时只能存在一个写锁但是可以存在多个读锁,但不能同时存在写锁和读锁。   如果读写锁当前没有读者,也没有写者,那么写者可以立刻获的读写锁,否则必须自旋,直到没有...

GarfieldEr007的专栏 754
上一篇: Spring(十二):bean的加载——创建bean
下一篇: Java并发(十一):读写锁——写锁
GDUT_Ember
博客等级 码龄6年 875粉丝 190原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值