ReentrantReadWriteLock

读写锁

独占锁X:指该锁一次只能被一个线程所持有,对 ReentrantLock 和 Synchronized 而言都是独占锁

共享锁S:指该锁可以被多个线程锁持有

ReentrantReadWriteLock 其读锁是共享锁,写锁是独占锁

作用:多个线程同时读一个资源类没有任何问题,为了满足并发量,读取共享资源应该同时进行,但是如果一个线程想去写共享资源,就不应该再有其它线程可以对该资源进行读或写

使用规则:

  • 加锁解锁格式:

     r.lock();try {// 临界区} finally {r.unlock();}
  • 读-读能共存、读-写不能共存、写-写不能共存【读锁保护数据的 read() 方法,写锁保护数据的 write() 方法】不同线程间读写是互斥的

  • 读锁不支持条件变量

  • 升级:获取读锁的情况下还想获取写锁; 降级:先获取写锁在获取读锁

  • 重入时升级不支持:持有读锁的情况下去获取写锁会导致获取写锁永久等待,需要先释放读,再去获得写【必须先释放掉读锁】

    • 【可能有多个线程在读,如果其中一个线程想升级,那其他的读线程就 会 很 难 办】

    • 【可以这样理解:因为读锁之间时兼容的,当前线程获得读锁的同时,其他线程可能也获得了读锁】

  • 重入时降级支持:持有写锁的情况下去获取读锁,造成只有当前线程会持有读锁,因为写锁会互斥其他的锁【写的时候能读,因为写锁只能被一个线程获取】

    • 在保证数据一致性的同时,尽量减少持有写锁的时间

    • 可以做到,因为此线程拿到写锁,只有本线程可以去申请读锁,其他线程拿不到锁了,因为读写不共存。源码中有判断是否时当前线程的if判断。

      • 见w.lock : c != 0 and w == 0 表示有读锁(之前有的),【读锁不能升级】,直接返回 false====从这里也能看出不能升级,也就是原先有了读锁还要尝试tryAcquire获取写锁。(不允许)

     w.lock();try {r.lock();// 降级为读锁, 释放写锁, 这样能够让其它线程读取缓存try {// ...} finally{w.unlock();// 要在写锁释放之前获取读锁}} finally{r.unlock();}

在同一个线程内部,情况则有所不同。对于ReentrantReadWriteLock这样的可重入读写锁来说,一个线程是可以先获取独占锁(写锁),然后在不释放该锁的情况下再次获取共享锁(读锁)的。这种情况下,线程仍然持有独占锁,但同时也可以进行读操作(因为它也持有了共享锁)。但请注意,这并不意味着独占锁和共享锁在同一时刻“共存”于同一个线程中,而是线程在内部以特定的方式管理了这两种锁的状态。

构造方法:

  • public ReentrantReadWriteLock():默认构造方法,非公平锁

  • public ReentrantReadWriteLock(boolean fair):true 为公平锁

常用API:

  • public ReentrantReadWriteLock.ReadLock readLock():返回读锁

  • public ReentrantReadWriteLock.WriteLock writeLock():返回写锁

  • public void lock():加锁

  • public void unlock():解锁

  • public boolean tryLock():尝试获取锁

读读并发:

 public static void main(String[] args) {ReentrantReadWriteLock rw = new ReentrantReadWriteLock();ReentrantReadWriteLock.ReadLock r = rw.readLock();ReentrantReadWriteLock.WriteLock w = rw.writeLock();​new Thread(() -> {r.lock();try {Thread.sleep(2000);System.out.println("Thread 1 running " + new Date());} finally {r.unlock();}},"t1").start();new Thread(() -> {r.lock();try {Thread.sleep(2000);System.out.println("Thread 2 running " + new Date());} finally {r.unlock();}},"t2").start();}


缓存应用

用读写锁实现既能保证一致性,又能不像加普通锁那样性能降低

缓存更新时,是先清缓存还是先更新数据库

  • 先清缓存:可能造成刚清理缓存还没有更新数据库,线程直接查询了数据库更新过期数据到缓存

  • 先更新据库:可能造成刚更新数据库,还没清空缓存就有线程从缓存拿到了旧数据【 但多做一次查询时可以把错纠正过来

  • 补充情况:查询线程 A 查询数据时恰好缓存数据由于时间到期失效,或是第一次查询

可以使用读写锁进行操作


成员属性原理

读写锁用的是同一个 Sycn(AQS) 同步器,因此等待队列、state 等也是同一个,原理与 ReentrantLock 加锁相比没有特殊之处,不同是写锁状态占了 state 的低 16 位,而读锁使用的是 state 的高 16 位【 state分成了两份,还是0--无锁 】

  • 读写锁:

     private final ReentrantReadWriteLock.ReadLock readerLock;       private final ReentrantReadWriteLock.WriteLock writerLock;
  • 构造方法:默认是非公平锁,可以指定参数创建公平锁

     public ReentrantReadWriteLock(boolean fair) {// true 为公平锁sync = fair ? new FairSync() : new NonfairSync();// 这两个 lock 共享同一个 sync 实例,都是由 ReentrantReadWriteLock 的 sync 提供同步实现readerLock = new ReadLock(this);writerLock = new WriteLock(this);}

Sync 类的属性:

  • 统计变量:

     // 用来移位static final int SHARED_SHIFT   = 16;// 高16位的1static final int SHARED_UNIT    = (1 << SHARED_SHIFT);// 65535,16个1,代表写锁的最大重入次数static final int MAX_COUNT      = (1 << SHARED_SHIFT) - 1;// 低16位掩码:0b 1111 1111 1111 1111,用来获取写锁重入的次数static final int EXCLUSIVE_MASK = (1 << SHARED_SHIFT) - 1;
  • 获取读写锁的次数:

     // 获取读写锁的读锁分配的总次数static int sharedCount(int c)    { return c >>> SHARED_SHIFT; }// 写锁(独占)锁的重入次数static int exclusiveCount(int c) { return c & EXCLUSIVE_MASK; }
  • 内部类:

     // 记录读锁线程自己的持有读锁的数量(重入次数),因为 state 高16位记录的是全局范围内所有的读线程获取读锁的总量static final class HoldCounter {int count = 0;// Use id, not reference, to avoid garbage retentionfinal long tid = getThreadId(Thread.currentThread());}// 线程安全的存放线程各自的 HoldCounter 对象static final class ThreadLocalHoldCounter extends ThreadLocal<HoldCounter> {public HoldCounter initialValue() {return new HoldCounter();}}
  • 内部类实例:

     // 当前线程持有的可重入读锁的数量,计数为 0 时删除private transient ThreadLocalHoldCounter readHolds;// 记录最后一个获取【读锁】线程的 HoldCounter 对象private transient HoldCounter cachedHoldCounter;
  • 首次获取锁:

     // 第一个获取读锁的线程private transient Thread firstReader = null;// 记录该线程持有的读锁次数(读锁重入次数)private transient int firstReaderHoldCount;
  • Sync 构造方法:

     Sync() {readHolds = new ThreadLocalHoldCounter();// 确保其他线程的数据可见性,state 是 volatile 修饰的变量,重写该值会将线程本地缓存数据【同步至主存】setState(getState()); }

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

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

相关文章

【快速入门】Transformer: Attention Is All You Need

Transformer → \to → 【知名应用】BERT (unsupervised trained Transformer) Transformer &#xff1a;seq2Seq model with self-attention, 后续会主要说明 self-attentionTransformer的组成&#xff1a; Self-attention是 Attention变体&#xff0c;擅长捕获数据/特征的内…

【容器化】docker和docker-compose/dockerfile和docker-compose.yml

文章目录 docker和docker-composeDockerDocker Compose总结 dockerfile和docker-compose.ymlDockerfiledocker-compose.yml示例Dockerfile 示例docker-compose.yml 示例 docker和docker-compose Docker和Docker Compose是两个重要的工具&#xff0c;用于容器化应用程序的开发、…

完整代码Python爬取豆瓣电影详情数据

完整代码Python爬取豆瓣电影详情数据 引言 在数据科学和网络爬虫的世界里&#xff0c;豆瓣电影是一个丰富的数据源。在本文中&#xff0c;我们将探讨如何使用Python语言&#xff0c;结合requests和pyquery库来爬取豆瓣电影的详情页面数据。我们将通过一个具体的电影详情页面作…

JavaScript关于bind解析

在 JavaScript 中&#xff0c;bind() 方法用于创建一个新的函数&#xff0c;该函数的 this 值被绑定到调用 bind() 方法的对象。bind() 方法的主要目的是修改函数的 this 指向。 bind() 方法可以接受一个或多个参数&#xff0c;第一个参数是要绑定的 this 值&#xff0c;后续的…

oracle11.2.0.4 RAC 保姆级静默安装(一) GI集群软件

一、响应文件准备 我们直接使用软件解压后的response文件夹中的响应文件模板进行修改 选择当前服务器的主机名,产品目录是在已存在的/u01/app目录基础上自动创建的无需提前创建oraInventory 按需选择语言,具体语言配置参考表格 一般rac默认选择安装类型为CRS_CONFIG 对应正…

借助 NGINX Unit 在服务器端使用 WebAssembly

原文作者&#xff1a;Liam Crilly of F5 原文链接&#xff1a;借助 NGINX Unit 在服务器端使用 WebAssembly 转载来源&#xff1a;NGINX 中文官网 NGINX 唯一中文官方社区 &#xff0c;尽在 nginx.org.cn WebAssembly&#xff08;缩写为 Wasm&#xff09;可为 Web 应用领域提供…

探索IPython的隐藏力量:精通%macro命令

探索IPython的隐藏力量&#xff1a;精通%macro命令 在IPython的强大世界中&#xff0c;存在着一些被称为“魔术命令”的特殊命令&#xff0c;它们扩展了Python的标准能力&#xff0c;让我们的交互式编程体验更加丰富和高效。其中&#xff0c;%macro命令是一个鲜为人知但极其有…

Vscode interaction window

python 代码关联到 jupyter 模式 在代码前添加&#xff1a; # %%print("hellow wolrd!") 参考文档链接&#xff1a; https://code.visualstudio.com/docs/python/jupyter-support-py

C++ 教程 - 06 类的封装、继承、多态

文章目录 封装继承多态 封装 在private/protected 模块放置数据或者底层算法实现&#xff1b;在public块提供对外接口&#xff0c;实现相应的功能调用&#xff1b;类的封装案例 #include <iostream> using namespace std;// 类的定义 一般放在头文件 class Stu {public…

3、广告-交易模式

一、交易模式种类&#xff08;Types of Transaction Models&#xff09; RTB实时竞价&#xff08;Real-Time Bidding, RTB&#xff09; RTB是程序化广告中最常见的交易模式之一。它通过实时竞价的方式&#xff0c;让广告主在广告展示前以竞拍的方式获取广告展示机会。每当有广告…

uniapp——上传图片获取到file对象而非临时地址——基础积累

最近在看uniapp的代码&#xff0c;遇到一个需求&#xff0c;就是要实现上传图片的功能 uniapp 官网地址&#xff1a;https://uniapp.dcloud.net.cn/ 上传图片有对应的API&#xff1a; uni.chooseImage方法&#xff1a;https://uniapp.dcloud.net.cn/api/media/image.html#choo…

筛斗数据:数据提取技术,构建智慧企业的基石

在信息化和数字化的浪潮下&#xff0c;企业面临着前所未有的机遇与挑战。为了在这场变革中立于不败之地&#xff0c;越来越多的企业开始转型为智慧企业&#xff0c;而数据提取技术正是构建智慧企业的关键基石。 一、数据提取技术的重要性 数据提取技术是指从各种数据源中自动…

零基础小白学习 Python,应该如何配置 Python 开发环境?(包含Windows、MacOS、Linux)

学习编程的第一步是配置一个良好的开发环境&#xff0c;尤其是对零基础的小白来说&#xff0c;一个简单而有效的开发环境能够帮助你快速上手&#xff0c;减少不必要的技术障碍。 1. 理解Python和开发环境 Python是一种高级编程语言&#xff0c;具有简单易学、功能强大的特点。…

LeetCode-数组/回溯-No40组合总和II

题目&#xff1a; 给定一个候选人编号的集合 candidates 和一个目标数 target &#xff0c;找出 candidates 中所有可以使数字和为 target 的组合。candidates 中的每个数字在每个组合中只能使用一次 。 注意&#xff1a;解集不能包含重复的组合。 示例 1: 输入: ca…

没有手机怎么办呐!高考成绩出来了:请不要吹灭别人的灯——早读(逆天打工人爬取热门微信文章解读)

结婚的时候红包随礼随多少呢 引言Python 代码第一篇 洞见 高考成绩出来了&#xff1a;请不要吹灭别人的灯第二篇结尾 为什么是这个标题呢&#xff1f; 是因为摸鱼看足球直播 主播好兄弟结婚 他老婆问他要红包 引言 今天早上停电了 大概是在3点多的时候 我本身一直都没有开空调…

Javac编译器

Java语言的编译器是一段不确定的操作过程&#xff0c;可能是讲Java文件转变为class文件的过程&#xff0c;也可能是指虚拟机的后端编译&#xff0c;讲字节码转换为机器码的过程&#xff0c;还肯是静态提前编译器直接讲Java文件编译为本地机器代码的过程。 前端编译器&#xff…

HTML5五十六个民族网站模板源码

文章目录 1.设计来源高山族1.1 登录界面演示1.2 注册界面演示1.3 首页界面演示1.4 中国民族界面演示1.5 关于高山族界面演示1.6 联系我们界面演示 2.效果和源码2.1 动态效果2.2 源代码2.3 源码目录 源码下载 作者&#xff1a;xcLeigh 文章地址&#xff1a;https://blog.csdn.ne…

TypeError: Object of type bytes is not JSON serializable

从您提供的错误跟踪信息来看&#xff0c;问题在于您尝试将一个bytes类型的对象作为JSON数据传递给requests.post方法的json参数。但是&#xff0c;json参数只接受可以被json.dumps序列化为JSON格式的Python数据类型&#xff08;如字典、列表、字符串、数字、None、True和False&…

FreeRTOS中任务控制块和任务句柄的作用

1. 任务控制块&#xff08;Task Control Block&#xff0c;TCB&#xff09; 任务控制块 是FreeRTOS内核用于管理任务的关键数据结构。它包含了任务执行所需的各种信息。每个任务对应一个唯一的TCB。 主要作用&#xff1a; 存储任务状态&#xff1a;TCB包含任务的当前状态信息…

数字化转型第三步:数字化业务创新与发展,提升收入和利润

引言&#xff1a;之前笔者的文章发布了企业数字化转型业务部分&#xff0c;如【开源节流】如何通过数字化转型增强盈利能力&#xff1f;企业供应链数字化转型如何做&#xff1f;让企业盈利能力增强再飞一会 【财务数字化转型之底座】集团企业财务数据中台系统建设方案 等文章&a…