【Java并发】聊聊ReentrantReadWriteLock锁降级和StampedLock邮戳锁

news2025/3/3 6:05:34

面试题
1.你说你用过读写锁,锁饥饿问题是什么?
2.有没有比读写锁更快的锁?
3.StampedLock知道吗?(邮戳锁/票据锁)
4.ReentrantReadWriteLock有锁降级机制策略你知道吗?

在并发编程领域,有多线程进行提升整体性能,但是却引入了共享数据安全性问题。基本就是无锁编程下的单线程操作,有互斥同步锁操作,但是性能不高,并且同一时刻只有一个线程可以操作资源类。但是对于大多数常见下,都是读操作多,写操作少,那么可以利用将锁的粒度进行细化,进而分化出读锁/写锁。也就是syn/ReentrantLock的升级版本ReentrantReadWriteLock。

读写锁

在这里插入图片描述

public class LockDemo {

    private static Map<Integer,Integer> cacheMap = new HashMap<>();
    private Lock lock = new ReentrantLock();
    private ReentrantReadWriteLock readWriteLock = new ReentrantReadWriteLock();


    public void write(Integer key, Integer value) {
        readWriteLock.writeLock().lock();
        try {
            System.out.println("当前"+key+"正在写入");
            Thread.sleep(500);
            cacheMap.put(key,value);
            System.out.println("当前"+key+"写入完毕");
        } catch (Exception e) {
            e.fillInStackTrace();
        } finally {
            readWriteLock.writeLock().unlock();
        }
    }

    public void read(Integer key) {
        readWriteLock.readLock().lock();
        try {
            System.out.println("当前"+key+"正在读取");
            cacheMap.get(key);
            System.out.println("当前"+key+"读取完毕");
        } catch (Exception e) {
            e.fillInStackTrace();
        } finally {
            readWriteLock.readLock().unlock();
        }
    }


    public static void main(String[] args) {
        LockDemo lockDemo  = new LockDemo();

        for (int i = 0; i < 10; i++) {
            int finalI = i;
            new Thread(()->{
                lockDemo.write(finalI, finalI);
            }).start();
        }

        for (int i = 0; i < 10; i++) {
            int finalI = i;
            new Thread(()->{
                lockDemo.read(finalI);
            }).start();
        }
    }

}

在这里插入图片描述
从执行结果来看,读锁不互斥。读取1的时候,还可以读取别的数据。

锁降级

锁降级是为了让当前线程感知到数据的变化,目的是保证数据可见性
在这里插入图片描述
在这里插入图片描述

public class LockDemo2 {

    public static void main(String[] args) {
        ReentrantReadWriteLock readWriteLock = new ReentrantReadWriteLock();
        ReentrantReadWriteLock.ReadLock readLock = readWriteLock.readLock();
        ReentrantReadWriteLock.WriteLock writeLock = readWriteLock.writeLock();

        readLock.lock();
        System.out.println("读取数据");
        readLock.unlock();
        writeLock.lock();
        System.out.println("写入数据");
        readLock.lock();
        System.out.println("读取数据");
        writeLock.unlock();
        readLock.unlock();
    }

}

调整顺序之后,读锁不能升级为写锁,但是写锁可以降级为读锁。
在这里插入图片描述

存在的问题

在这里插入图片描述
为了解决读写锁,锁饥饿的问题,解决方案有两个,1.通过使用公平锁来解决,但是公平锁会牺牲系统吞吐量为代价的。
2.使用stampedLock邮戳锁。
在这里插入图片描述

stampedlock

代表了锁的状态。当stamp返回零时,表示线程获取锁失败。并且,当释放锁或者转换锁的时候,都要传入最初获取的stamp值。

因为读写lock,虽然可以提升一定的性能,但是因为存在饥饿的问题,读写互斥。而邮戳锁是一种乐观锁,使用类似版本校验的机制,选判断数据有没有修改,没有修改直接读取,有修改则升级为悲观读取。其实是一种权衡。

StampedLock有三种访问模式
①Reading(读模式):功能和ReentrantReadWriteLock的读锁类似
②Writing(写模式):功能和ReentrantReadWriteLock的写锁类似
③**Optimistic reading(乐观读模式):无锁机制,类似于数据库中的乐观锁,**支持读写并发,很乐观认为读取时没人修改,假如被修改再实现升级为悲观读模式

StampedLock的缺点

  • StampedLock 不支持重入,没有Re开头
  • StampedLock 的悲观读锁和写锁都不支持条件变量(Condition),这个也需要注意。
  • 使用 StampedLock一定不要调用中断操作,即不要调用interrupt() 方法
    • 如果需要支持中断功能,一定使用可中断的悲观读锁 readLockInterruptibly()和写锁writeLockInterruptibly()

小结

本篇主要介绍了读写锁,以及读写锁的锁饥饿问题,为了进一步提升性能引入了邮戳锁,但是邮戳锁不支持重入和中断等。

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

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

相关文章

c++ - 抽象类 和 多态当中一些问题

抽象类 纯虚函数 在虚函数的后面写上 0 &#xff0c;则这个函数为纯虚函数。 class A { public:virtual void func() 0; }; 纯虚函数不需要写函数的定义&#xff0c;他有类似声明一样的结构。 抽象类概念 我们把具有纯虚函数的类&#xff0c;叫做抽象类。 所谓抽象就是&a…

124个Python案例,完整源代码!

大家好&#xff0c;我是涛哥。 很多小伙伴为了掌握爬虫这门技术&#xff0c;投入了大量的时间和精力。他们在深夜里独自码字&#xff0c;他们在周末的时候熟读代码&#xff0c; 但独自学习&#xff0c;没有朋友的陪伴和指导&#xff0c;学习的过程就像是在一条无尽的道路上徘…

【多线程】wait 、notify 和 notifyAll 讲解

wait 、notify 和 notifyAll 讲解 一. wait二. wait 和 sleep 的对比三. notify四. notifyAll五. notify 与 notifyAll 的原理 由于线程之间是抢占式执行的, 因此线程之间执行的先后顺序难以预知. 但是实际开发中有时候我们希望合理的协调多个线程之间的执行先后顺序. 完成这个…

军队状态出现的六种结果,是将帅的过失

军队状态会出现六种坏结果&#xff0c;是将帅的过失 【安志强趣讲《孙子兵法》第35讲】 【原文】 故兵有走者&#xff0c;有弛者&#xff0c;有陷者&#xff0c;有崩者&#xff0c;有乱者&#xff0c;有北者。凡此六者&#xff0c;非天之灾&#xff0c;将之过也。 【趣讲白话】…

【代码分析】初学解惑C++:函数适配器

文章目录 前置知识 运算符的重载“&#xff08;&#xff09;”一、函数适配器是什么&#xff1f;由遇到的问题引出适配器模式类模式对象模式例1例2例3例4二、实现函数适配器1.定义函数2.定义函数适配器3.使用函数适配器 三、带模板的函数适配器1、自定义unary_function2、改写带…

alibaba按关键字搜索商品 API

为了进行电商平台 的API开发&#xff0c;首先我们需要做下面几件事情。 1&#xff09;开发者注册一个账号 2&#xff09;然后为每个alibaba应用注册一个应用程序键&#xff08;App Key) 。 3&#xff09;下载alibaba API的SDK并掌握基本的API基础知识和调用 4&#xff09;利…

vue3中,调接口,渲染数据

1. 封装接口文档 // src/apis/xxx.js中 // 1. 导入 封装的axios实例 import request from /utils/http // 2. 封装接口 --获取轮播图数据 export const getBannerAPI (params {})>{// 传默认参数->&#xff08;传参 默认参数&#xff09;const { distributionSite…

Reids的安装使用

Windows 版本的 Redis 是 Microsoft 的开源部门提供的 Redis. 这个版本的 Redis 适合开发人员学习使用&#xff0c;生产环境中使用 Linux 系统上的 Redis, 这里讲解了这两种的安装和下载。按照你们需要的liunx 或window步骤来 就可以了&#xff08;也可以留言&#xff0c;后面看…

c++ explicit关键作用

explicit 概念引入1.explicit 介绍1.1 显示调用和隐式调用1.2 explicit意义 概念引入 构造函数不仅可以构造并初始化对象&#xff0c;对于具有单个参数或者除第一个参数无默认值其余均有默认值的构造函数&#xff0c;还具有类型转换作用。 而explicit关键字&#xff0c;恰恰可…

useGetState自定义hooks解决useState 异步回调获取不到最新值

setState 的两种传参方式 1、直接传入新值 setState(options); const [state, setState] useState(0); setState(state 1); 2、传入回调函数 setState(callBack); const [state, setState] useState(0); setState((prevState) > prevState 1); // prevState 是改变之…

BUUCTF reverse2 1

使用die查看文件信息&#xff0c;发现是ELF64位程序&#xff0c; 也就是说这是linux上的运行程序 再linux上运行 使用IDA64打开文件 F5 反编译 可以看到这里和flag进行对比 点击flag 点击这个7Bh&#xff0c;然后按r flag出来了 {hacking_for_fun}加上flag头提交 flag{h…

Python入门教程35:使用email模块发送HTML和图片邮件

smtplib模块实现邮件的发送功能&#xff0c;模拟一个stmp客户端&#xff0c;通过与smtp服务器交互来实现邮件发送的功能&#xff0c;可以理解成Foxmail的发邮件功能&#xff0c;在使用之前我们需要准备smtp服务器主机地址、邮箱账号以及密码信息。 #我的Python教程 #官方微信公…

用Canape配置VX1000的工程,在DA中绘制各个传感器目标的方法

参考本文档可帮助读者,快速安装VX1000软件,根据自己的需求,实现传感器目标在canape中DA的绘制。 介绍 Driver assistance (DA)系统是通过各种传感器(如视频、雷达、激光雷达等)获取有关车辆环境的信息。根据传感器对物体检测的结果(例如与前方车辆的距离)对驾驶员发…

《C++ Core Guidelines解析》:揭示现代C++最佳实践的深层原理

本书旨在深入解析C Core Guidelines&#xff0c;这是C社区中权威的编程指南。我们将探索其中所包含的现代C最佳实践&#xff0c;从底层原理和设计理念角度剖析其背后的思想。通过对Guidelines的逐条解析和实例说明&#xff0c;读者将深入理解如何编写更安全、高效和可维护的C代…

滑动窗口的最大值(双端队列,单调队列)

力扣&#xff08;LeetCode&#xff09;官网 - 全球极客挚爱的技术成长平台 class Solution {public int[] maxSlidingWindow(int[] nums, int k) {LinkedList<Integer> deque new LinkedList<>();//双端队列&#xff0c;存储单调队列的下标int ans[] new int[nu…

Android Studio 导入工程Gradle和JDK配置修改工程名称修改包名

一、Gradle 配置 经常遇到导入的工程却编译不过&#xff0c;很多情况下就是因为配置不一样导致有问题&#xff0c;主要有两个配置&#xff1a; Android Gradle Plugin Version Gradle Version 找一个能正常运行的项目&#xff0c;把它两配置成一样&#xff0c;一般都能解决问…

openssl命令行:RSA的用法-- 终极版

1、生成密钥 openssl genrsa -out test2048_priv.pem 2048 openssl rsa -pubout -in test2048_priv.pem -out test2048_pub.pem openssl genrsa -out test3072_priv.pem 3072 openssl rsa -pubout -in test3072_priv.pem -out test3072_pub.pem openssl genrsa -out test4096…

双系统 + Ubuntu20.04 + ros2 (foxy) git clone -b连接不成功的解决

一、问题描述 虚拟机已经跑通turtlebot3&#xff0c;能成功进行编译&#xff0c;进而执行自主避障&#xff0c;启动house地图&#xff0c;SLAM建图&#xff0c;SLAM导航等任务。但由于虚拟机加载gazebo模型太慢&#xff0c;且考虑到后面计划进行多机通讯&#xff0c;故配置双系…

解决table 操作栏塌陷的问题

1. el-table 塌陷 2. 解决办法 是通过查看官网,看见有一个重新布局的方法 https://element.eleme.cn/#/zh-CN/component/table 3. 代码实现 先将table 绑定ref 调用ref 方法 就ok了

Tomcat服务的部署及配置优化

文章目录 1. Tomcat的相关介绍1.1 Tomcat简介1.2 Tomcat的核心组件1.2.1 Web容器1.2.2 Servlet容器1.2.3 JSP容器 1.3 Tomcat的功能组件1.3.1 connector连接器1.3.2 container容器1.3.2.1 子容器及其相关功能 1.4 主要作用1.5 Tmocat处理请求的过程 2. Tomcata服务部署2.1 安装…