AQS之ReentrantReadWriteLock

AQS之ReentrantReadWriteLock

一. 归纳总结

  1. ReentrantReadWriteLock适合读多写少的场景。是可重入的读写锁实现类。其中, 写锁是独占的,读锁是共享的。

  2. 支持锁降级(持有写锁、获取读锁,最后释放写锁的过程)

  • 锁降级可以帮助我们拿到当前线程修改后的结果而不被其他线程所破坏,防止更新丢失。
  • 可以保证数据的可见性,如果当前线程不获取读锁而是直接释放写锁,假设此刻另一个线程(记作线程T)获取了写锁并修改了数据,那么当前线程无法感知线程T的数据更新。如果当前线程获取读锁,即遵循锁降级的步骤,则线程T将会被阻塞,直到当前线程使用数据并释放读锁之后,线程T才能获取写锁进行数据更新。
  1. 不支持锁升级(持有读锁、获取写锁,最后释放读锁的过程)
    目的也是保证数据可见性,如果读锁已被多个线程获取,其中任意线程成功获取了写锁并更新了数据,则其更新对其他获取到读锁的线程是不可见的。

二.读写状态的设计

读写锁对于同步状态的实现是在一个整形变量上通过“按位切割使用”:将变量切割成两部分,高16位表示读,低16位表示写。
在这里插入图片描述
假设当前同步状态值为S,get和set的操作如下:

1、获取写状态:

S&0x0000FFFF:将高16位全部抹去

2、获取读状态:

S>>>16:无符号补0,右移16位

3、写状态加1:

 S+1

4、读状态加1:

S+(1<<16)即S + 0x00010000

在代码层面的判断中,同步状态S不等于0时,当写状态(S&0x0000FFFF)等于0时,则读状态(S>>>16)大于0,即读锁已被获取。

三.写锁的获取与释放

3.1 写锁的获取

  • 写锁是一个支持重进入的排它锁。如果当前线程已经获取了写锁,则增加写状态。如果当前线程在获取写锁时,读锁已经被获取(读状态不为0)或者该线程不是已经获取写锁的线程, 则当前线程进入等待状态。
  • 写锁的获取是通过重写AQS中的tryAcquire方法实现的。
protected final boolean tryAcquire(int acquires) {//当前线程Thread current = Thread.currentThread();//获取state状态   存在读锁或者写锁,状态就不为0int c = getState();//获取写锁的重入数int w = exclusiveCount(c);//当前同步状态state != 0,说明已经有其他线程获取了读锁或写锁if (c != 0) {// c!=0 && w==0 表示存在读锁// 当前存在读锁或者写锁已经被其他写线程获取,则写锁获取失败if (w == 0 || current != getExclusiveOwnerThread())return false;// 超出最大范围  65535if (w + exclusiveCount(acquires) > MAX_COUNT)throw new Error("Maximum lock count exceeded");//同步state状态setState(c + acquires);return true;}// writerShouldBlock有公平与非公平的实现, 非公平返回false,会尝试通过cas加锁//c==0 写锁未被任何线程获取,当前线程是否阻塞或者cas尝试获取锁 if (writerShouldBlock() ||!compareAndSetState(c, c + acquires))return false;//设置写锁为当前线程所有setExclusiveOwnerThread(current);return true;

源码分析:

  • 读写互斥
  • 写写互斥
  • 写锁支持同一个线程重入
  • writerShouldBlock写锁是否阻塞实现取决公平与非公平的策略(FairSync和NonfairSync)
    在这里插入图片描述

3.2 读锁的获取

实现共享式同步组件的同步语义需要通过重写AQS的tryAcquireShared方法和tryReleaseShared方法。读锁的获取实现方法为:

protected final int tryAcquireShared(int unused) {Thread current = Thread.currentThread();int c = getState();// 如果写锁已经被获取并且获取写锁的线程不是当前线程,当前线程获取读锁失败返回-1   判断锁降级if (exclusiveCount(c) != 0 &&getExclusiveOwnerThread() != current)return -1;//计算出读锁的数量int r = sharedCount(c);/*** 读锁是否阻塞    readerShouldBlock()公平与非公平的实现* r < MAX_COUNT: 持有读锁的线程小于最大数(65535)*  compareAndSetState(c, c + SHARED_UNIT) cas设置获取读锁线程的数量*/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);

源码分析:

  • 读锁共享,读读不互斥
  • 读锁可重入,每个获取读锁的线程都会记录对应的重入数
  • 读写互斥,锁降级场景除外
  • 支持锁降级,持有写锁的线程,可以获取读锁,但是后续要记得把读锁和写锁读释放
  • readerShouldBlock读锁是否阻塞实现取决公平与非公平的策略(FairSync和NonfairSync)
    在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/586234.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

2023-12-30 msys2的python包降级

点击 <C 语言编程核心突破> 快速C语言入门 msys2的python包降级 前言总结 前言 要解决问题: 调大模型, 要用python, 需要numpy安装pip结果是升级了, 对不上当前py版本, 啥都装不了, 需要降级. 想到的思路: https://repo.msys2.org/mingw/clang64/ 下载对应包 使用命令…

oracle-存储结构

文件包括 控制文件.ctl、数据文件.dbf、日志文件.log这三类放在存储上。 参数文件&#xff1a;空间的划分&#xff0c;进程的选用&#xff08;.ora&#xff09; oracle启动的时候需要读一下&#xff0c;数据库启动后&#xff0c;参数文件并不关闭&#xff0c;但即使文件丢了&a…

Python生成器 (Generators in Python)

Generators in Python 文章目录 Generators in PythonIntroduction 导言贯穿全文的几句话为什么 Python 有生成器Generator&#xff1f;如何获得生成器Generator&#xff1f;1. 生成器表达式 Generator Expression2. 使用yield定义生成器Generator 更多Generator应用实例表示无…

车牌识别技术,如何用python识别车牌号

目录 一.前言 二.运行环境 三.代码 四.识别效果 五.参考 一.前言 车牌识别技术&#xff08;License Plate Recognition, LPR&#xff09;在交通计算机视觉&#xff08;Computer Vision, CV&#xff09;领域具有非常重要的研究意义。以下是该技术的一些扩展说明&#xff1…

Day20 222完全二叉树的节点个数 110平衡二叉树 257二叉树的所有路径

222 完全二叉树的结点个数 本题先不把它当成完全二叉树来看&#xff0c;用广度优先和深度优先搜索分别遍历&#xff0c;也能达到目的&#xff0c;只要将之前的代码稍加修改即可。注意后序遍历时的result要加上自身本身的那个结点。 //后序递归遍历 class Solution { public:in…

【AI】人工智能的未来

目录 一、人工智能的未来预测 二、可信人工智能 三、多模态预训练模型 四、基于人工智能的网络安全 五、边缘计算和联合学习 六、人机协作与交互 七、从大数据转向多样化小数据 八、人工智能伦理 一、人工智能的未来预测 从技术的发展角度看&#xff0c;人工智能&…

STL——集合算法

算法简介&#xff1a; set_intersection // 求两个容器的交集set_union // 求两个容器的并集set_difference // 求两个容器的差集 1.set_intersection 函数原型&#xff1a; set_intersection(iterator beg1, iterator end1, iterator beg2, iterator end2, iterator dest);…

【办公技巧】怎么批量提取文件名到excel

Excel是大家经常用来制作表格的文件&#xff0c;比如输入文件名&#xff0c;如果有大量文件需要输入&#xff0c;用张贴复制或者手动输入的方式还是很费时间的&#xff0c;今天和大家分享如何批量提取文件名。 打开需要提取文件名的文件夹&#xff0c;选中所有文件&#xff0c…

iptables 防火墙(二)

目录 1. SNAT 策略及应用 1.1 SNAT策略概述 1. 只开启路由转发&#xff0c;未设置地址转换的情况 2. 开启路由转发&#xff0c;并设置SNAT转换的情况 1.2 SNAT策略的应用 1. 2.1 共享固定IP上网 &#xff08;1&#xff09;打开网关的路由转发 &#xff08;2&#xff09;…

SQL进阶:视图的增删改

上一节我们学习了子查询,这一节我们来了解下视图。这俩货很像。 当子查询很复杂,用的地方又多,为了提高重用率,就可以创建为视图。当然了,视图还有其他用处。 视图的用途 简化查询,这个上面已经提到了。 保护数据,可以通过视图来开放给用户指定的列,来缩小访问权限…

MongoDB 概念介绍

1、MongoDB 应用场景 传统的关系型数据库&#xff0c;在数据操作的"三高"需求以及应对Web2.0的网站需求面前&#xff0c;显得力不从心。 High performance -对数据库高并发读写的需求。Huge Storage -对海量数据的高效率存储和访问的需求。High Scalability &&…

servlet总结

目录 1.生命周期 2.线程总结 3.配置 4.请求和响应 5.会话管理 6.过滤和监听器 7.处理表单数据 8.与JSP集成 9.异常处理 10.安全性和认证 Servlet是一种基于Java的Web组件&#xff0c;用于处理客户端请求并生成动态Web内容。以下是关于Servlet的一些总结 1.生命周期 …

Java核心知识点1-java和c++区别、隐式和显示类型转换

java和c区别 java通过虚拟机实现跨平台特性&#xff0c;但c依赖于特定的平台。java没有指针&#xff0c;它的引用可以理解为安全指针&#xff0c;而c和c一样具有指针。java支持自动垃圾回收&#xff0c;而c需要手动回收。java不支持多重继承&#xff0c;只能通过实现多个接口来…

【PHP】函数array_intersect、array_diff:从数组中取出、去除指定的几个键值

1.从数组中取出 &#xff1a;array_intersect 要从数组中取出指定的几个键值&#xff0c;可以使用 array_intersect_key 函数。以下是一个示例&#xff1a; $array [name > John,age > 30,email > johnexample.com,city > New York ];$keys [name, email];$resu…

C++进阶--二叉树进阶(二叉搜索树)

二叉树进阶&#xff08;二叉搜索树&#xff09; 一、二叉搜索树1.1 二叉搜索树的概念 二、二叉搜索树的结构2.1 结点结构2.2 树结构 三、二叉搜索树的操作&#xff08;非递归&#xff09;3.1 二叉搜索树的插入3.2 二叉搜索树的查找3.3 二叉搜索树的中序遍历3.4 二叉搜索树的删除…

c++学习笔记-提高篇-STL-函数对象

目录 一、函数对象 二、函数对象使用 三、谓词 1、概念 2、一元谓词 3、二元谓词 插入一条sort函数源码 四、内建函数对象 1.基本概念 2、算数仿函数 3、关系仿函数 4、逻辑仿函数 一、函数对象 函数对象概念 &#xff08;1&#xff09;重载函数调用操作符的类&a…

WPF+Halcon 培训项目实战(11):HS组件封装

文章目录 前言相关链接项目专栏运行环境匹配图片封装组件新增类库项目选择依赖顺序并添加Nuget修改原本矩形方法运行结果&#xff1a; 对矩形进行抽象封装抽象基类矩形抽象改造 圆形抽象封装代码运行结果 前言 为了更好地去学习WPFHalcon&#xff0c;我决定去报个班学一下。原…

Baumer工业相机堡盟工业相机如何通过NEOAPI SDK设置相机的固定帧率(C++)

Baumer工业相机堡盟工业相机如何通过NEOAPI SDK设置相机的固定帧率&#xff08;C&#xff09; Baumer工业相机Baumer工业相机的固定帧率功能的技术背景CameraExplorer如何查看相机固定帧率功能在NEOAPI SDK里通过函数设置相机固定帧率 Baumer工业相机通过NEOAPI SDK设置相机固定…

react基础学习 附加todo实现代码

简介 学习目的 我们在学习GUI开发的时候一般思考两个问题 如何来设计UI?如何实现前后端数据交互? 问题一 React引入了tsx语法,让我们能够在ts中自由的嵌入html,让我们能只写tsx代码,来实现UI的控制,而不是把所有的UI都放进一个html文件中,让各个部分更好维护 所react中…

Kubernetes 中整合 Istio 的全面指南

大家好&#xff0c;我是升仔 Istio 在 Kubernetes 的关键应用场景 服务间通信的精细控制&#xff1a;Istio 提供路由规则、重试、故障转移和断路器等功能&#xff0c;用于控制和优化服务间的通信。安全性强化&#xff1a;提供了强大的服务间认证和授权功能&#xff0c;确保只…