JUC之ReentrantReadWriteLock

2023-11-13

JUC之ReentrantReadWriteLock

1.背景

由于ReentrantLock是独占可重入锁,因此在进行操作的时候,不能够满足多线程同时操作数据,为了满足并发场景下的临界资源的数据共享,出现了ReentrantReadWriteLock共享锁。ReentrantReadWriteLock是ReadWriteLock接口的实现类,ReadWriteLock提供了readLock,writeLock两种方法。

2.共享锁

共享锁:即多个线程可以同时操作共享数据,但是存在这样的前置条件:读读共享,读写互斥,写读互斥,写写互斥。

小例子测试:

步骤一:先获取读写锁

private ReadWriteLock rw = new ReentrantReadWriteLock();

步骤二:创建读锁

private Lock r = rw.readLock();

步骤三:创建写锁

private Lock w = rw.writeLock();

步骤四:定义临界资源

private volatile int num = 0;

步骤五:创建读操作

public int getNum() {
        r.lock();
        System.out.println("当前线程获取读锁==" + Thread.currentThread().getName());
        try {
            try {
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return num;
        } finally {
            System.out.println("当前读取数据结束==" + Thread.currentThread().getName());
            r.unlock();
        }

步骤六:创建写操作

public void setNum() {
    w.lock();
    System.out.println("当前线程获取写锁==" + Thread.currentThread().getName());
    try {
        num++;
    } finally {
        System.out.println("当前线程释放写锁" + Thread.currentThread().getName());
        w.unlock();
    }

步骤七:编写main函数

public static void main(String[] args) {
    ReentrantReadWriteLockDemo reentrantReadWriteLockDemo = new ReentrantReadWriteLockDemo();

    new Thread(() -> {
        reentrantReadWriteLockDemo.getNum();
    }).start();
    new Thread(() -> {
        reentrantReadWriteLockDemo.getNum();
    }).start();
    new Thread(() -> {
        reentrantReadWriteLockDemo.getNum();
    }).start();
    new Thread(() -> {
        reentrantReadWriteLockDemo.getNum();
    }).start();

}

测试:

1.读读共享
在这里插入图片描述

可以看到读读是共享的,也就是说可以同时获取共享资源。

2.读写互斥、写读互斥

​ 更改某个线程,调用写操作
在这里插入图片描述

​ 可以看到读写是互斥的。简而言之,当读的时候,写需要等待,当读释放锁,写才可以获取,当写释放才可以读。

3.写写互斥
在这里插入图片描述

​ 获取和释放写锁串行执行。

3.锁降级

在可重入读写锁中存在锁降级的情况,也就是说如果当前线程持有写锁,在不释放写锁的情况下,还可以占据读锁。

测试

增加一个共享变量flag,并完成锁降级。锁降级的顺序是:获取写锁->获取读锁->释放写锁->释放读锁。【一定要是这个过程,否则会出现脏读,也就是当线程A获取写锁执行完逻辑后,释放写锁,如果此时线程B获取写锁后,对数据完成修改,当线程A获取了线程B已经修改的数据,此时就出现了脏读】

package JUC;

import ThreadDemo.ThreadAl;

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;

/**
 * 测试读写锁的demo
 */
public class ReentrantReadWriteLockDemo {
    private  volatile  boolean flag=false;
    private volatile int num = 0;
    //创建读写锁
    private ReadWriteLock rw = new ReentrantReadWriteLock();
    //获取读锁
    private Lock r = rw.readLock();
    //获取写锁
    private Lock w = rw.writeLock();


    public int getNum() {
        r.lock();
        System.out.println("当前线程获取读锁==" + Thread.currentThread().getName());
        try {
            try {
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return num;
        } finally {
            System.out.println("当前读取数据结束==" + Thread.currentThread().getName());
            r.unlock();
        }
    }

    public void setNum() {
        w.lock();
        System.out.println("当前线程获取写锁==" + Thread.currentThread().getName());
        try {
            num++;
  					r.lock();
            System.out.println("写锁降级,获取读锁成功,Thread===="+Thread.currentThread().getName());
        } finally {
            System.out.println("当前线程释放写锁" + Thread.currentThread().getName());
            w.unlock();
        }
        try{
            if(flag){
                System.out.println("【执行业务逻辑,写锁降级为读锁】");
            }
        }finally {
            r.unlock();
            System.out.println("写锁降级,释放读锁成功,Thread===="+Thread.currentThread().getName());

        }
    }

    public static void main(String[] args) {
        ReentrantReadWriteLockDemo reentrantReadWriteLockDemo = new ReentrantReadWriteLockDemo();
        new Thread(() -> {
            reentrantReadWriteLockDemo.getNum();
        }).start();
        new Thread(() -> {
            reentrantReadWriteLockDemo.setNum();
        }).start();
        new Thread(() -> {
            reentrantReadWriteLockDemo.flag = true;
        }).start();

        new Thread(() -> {
            reentrantReadWriteLockDemo.getNum();
        }).start();

    }
}

运行结果:
在这里插入图片描述

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

JUC之ReentrantReadWriteLock 的相关文章

  • Java 中等效的并行扩展

    我在 Net 开发中使用并行扩展有一些经验 但我正在考虑在 Java 中做一些工作 这些工作将受益于易于使用的并行库 JVM 是否提供任何与并行扩展类似的工具 您应该熟悉java util concurrent http java sun
  • java.lang.NoClassDefFoundError:org.apache.batik.dom.svg.SVGDOMImplementation

    我在链接到我的 Android LibGDX 项目的 Apache Batik 库时遇到了奇怪的问题 但让我们从头开始 在 IntelliJ Idea 中我有一个项目 其中包含三个模块 Main Android 和 Desktop 我强调的
  • 为什么 i++ 不是原子的?

    Why is i Java 中不是原子的 为了更深入地了解 Java 我尝试计算线程中循环的执行频率 所以我用了一个 private static int total 0 在主课中 我有两个线程 主题 1 打印System out prin
  • Java中反射是如何实现的?

    Java 7 语言规范很早就指出 本规范没有详细描述反射 我只是想知道 反射在Java中是如何实现的 我不是问它是如何使用的 我知道可能没有我正在寻找的具体答案 但任何信息将不胜感激 我在 Stackoverflow 上发现了这个 关于 C
  • Java EE:如何获取我的应用程序的 URL?

    在 Java EE 中 如何动态检索应用程序的完整 URL 例如 如果 URL 是 localhost 8080 myapplication 我想要一个可以简单地将其作为字符串或其他形式返回给我的方法 我正在运行 GlassFish 作为应
  • 如何找到给定字符串的最长重复子串

    我是java新手 我被分配寻找字符串的最长子字符串 我在网上研究 似乎解决这个问题的好方法是实现后缀树 请告诉我如何做到这一点或者您是否有任何其他解决方案 请记住 这应该是在 Java 知识水平较低的情况下完成的 提前致谢 附 测试仪字符串
  • 在 HTTPResponse Android 中跟踪重定向

    我需要遵循 HTTPost 给我的重定向 当我发出 HTTP post 并尝试读取响应时 我得到重定向页面 html 我怎样才能解决这个问题 代码 public void parseDoc final HttpParams params n
  • Android:捕获的图像未显示在图库中(媒体扫描仪意图不起作用)

    我遇到以下问题 我正在开发一个应用程序 用户可以在其中拍照 附加到帖子中 并将图片保存到外部存储中 我希望这张照片也显示在图片库中 并且我正在使用媒体扫描仪意图 但它似乎不起作用 我在编写代码时遵循官方的Android开发人员指南 所以我不
  • INSERT..RETURNING 在 JOOQ 中不起作用

    我有一个 MariaDB 数据库 我正在尝试在表中插入一行users 它有一个生成的id我想在插入后得到它 我见过this http www jooq org doc 3 8 manual sql building sql statemen
  • 加速代码 - 3D 数组

    我正在尝试提高我编写的一些代码的速度 我想知道从 3d 整数数组访问数据的效率如何 我有一个数组 int cube new int 10 10 10 我用价值观填充其中 然后我访问这些值数千次 我想知道 由于理论上所有 3d 数组都存储在内
  • 控制Android的前置LED灯

    我试图在用户按下某个按钮时在前面的 LED 上实现 1 秒红色闪烁 但我很难找到有关如何访问和使用前置 LED 的文档 教程甚至代码示例 我的意思是位于 自拍 相机和触摸屏附近的 LED 我已经看到了使用手电筒和相机类 已弃用 的示例 但我
  • Liferay ClassNotFoundException:DLFileEntryImpl

    在我的 6 1 0 Portal 实例上 带有使用 ServiceBuilder 和 DL Api 的 6 1 0 SDK Portlet 这一行 DynamicQuery query DynamicQueryFactoryUtil for
  • Java按日期升序对列表对象进行排序[重复]

    这个问题在这里已经有答案了 我想按一个参数对对象列表进行排序 其日期格式为 YYYY MM DD HH mm 按升序排列 我找不到正确的解决方案 在 python 中使用 lambda 很容易对其进行排序 但在 Java 中我遇到了问题 f
  • JRE 系统库 [WebSphere v6.1 JRE](未绑定)

    将项目导入 Eclipse 后 我的构建路径中出现以下错误 JRE System Library WebSphere v6 1 JRE unbound 谁知道怎么修它 右键单击项目 特性 gt Java 构建路径 gt 图书馆 gt JRE
  • 使用Caliper时如何指定命令行?

    我发现 Google 的微型基准测试项目 Caliper 非常有趣 但文档仍然 除了一些示例 完全不存在 我有两种不同的情况 需要影响 JVM Caliper 启动的命令行 我需要设置一些固定 最好在几个固定值之间交替 D 参数 我需要指定
  • getResourceAsStream() 可以找到 jar 文件之外的文件吗?

    我正在开发一个应用程序 该应用程序使用一个加载配置文件的库 InputStream in getClass getResourceAsStream resource 然后我的应用程序打包在一个 jar文件 如果resource是在里面 ja
  • 总是使用 Final?

    我读过 将某些东西做成最终的 然后在循环中使用它会带来更好的性能 但这对一切都有好处吗 我有很多地方没有循环 但我将 Final 添加到局部变量中 它会使速度变慢还是仍然很好 还有一些地方我有一个全局变量final 例如android Pa
  • 如何在桌面浏览器上使用 webdriver 移动网络

    我正在使用 selenium webdriver 进行 AUT 被测应用程序 的功能测试自动化 AUT 是响应式网络 我几乎完成了桌面浏览器的不同测试用例 现在 相同的测试用例也适用于移动浏览器 因为可以从移动浏览器访问 AUT 由于它是响
  • 编译器抱怨“缺少返回语句”,即使不可能达到缺少返回语句的条件

    在下面的方法中 编译器抱怨缺少退货声明即使该方法只有一条路径 并且它包含一个return陈述 抑制错误需要另一个return陈述 public int foo if true return 5 鉴于Java编译器可以识别无限循环 https
  • 如何修复 JNLP 应用程序中的“缺少代码库、权限和应用程序名称清单属性”?

    随着最近的 Java 更新 许多人都遇到了缺少 Java Web Start 应用程序的问题Codebase Permissions and Application name体现属性 尽管有资源可以帮助您完成此任务 但我找不到任何资源综合的

随机推荐

  • 2015年5月5日备忘录(主要是操作svg和设备仿真的physx参数)

    1 osg嵌套QT 使QT解析svg时 用osg绘制 2 cmake rsvg 3 dll a如何转换成 lib 再链接到 4 寻找 osgdb rsvg工程 5 windows下编译gtk 看看是否能生成rsvg lib 6 makefi
  • Python特征工程

    文章目录 一 自动化EDA 二 准备工作 一 合并数据 二 groupby聚合观察数据特征 三 去重 四 按列排序 五 随机抽数 六 保存 创建 与拼接 七 转换数据格式 八 删除列 三 特征中的异常值处理 一 箱线图公式处理异常值 1 删
  • centos 7 安装 Confluence 过程记录

    这段时间想建立一个资料库 对比了一下最终选择了Confluence 趁着放假时间整理了一下笔记 方便以后查询 顺便分享一下 目录 一 小插曲 二安装用到的软件 三 安装数据库 3 1卸载MariaDB 3 2安装MySQL 四 安装Conf
  • mysql开启和关闭远程访问权限

    文章目录 说明 用的是 navicat 连接工具 1 mysql开启远程访问权限 1 1 改表法 1 2 语句更改 2 mysql关闭远程访问权限 2 1 改表法 2 2 语句更改 说明 用的是 navicat 连接工具 先来看下mysql
  • Unity3D实践系列07,组件的启用或禁用开关,物体的的可见或不可见开关,以及相应事件...

    创建一个Unity项目 在 Project 窗口中 在 Asserts 中 添加 MyScene 文件夹 点击 File 中的 Save Scene 给Scene命名 并保存到 MyScene 文件夹 创建一个类型为 Plane 的Game
  • jsp的基本认识与理解

    简介 JSP全称是JavaServer Pages 它和servlet技术一样 都是SUN公司定义的一种用于开发动态web资源的技术 JSP这门技术的最大的特点在于 写jsp就像在写html 但 它相比html而言 html只能为用户提供静
  • 阿里云Windows Server 利用Subversion和TortoiseSVN部署SVN服务器

    SVN 全称为 SubVersion 是一个开源的版本控制系统 管理着随时间而改变更新的数据 这些数据都放置在一个中央资料档案库 repository 中 它类似于一个普通的文件服务器 可以记录每一次文件的更 新变动 这样就可以把档案恢复到
  • rabbitmq取消自动重连_RabbitMQ Java客户端自动重新连接

    When my application looses connection to RabbitMQ I have its connection factory set to automatically try and reconnect C
  • 小白也能弄懂的目标检测之YOLO系列 - 第一期

    大家好 上期分享了电脑端几个免费无广告且实用的录屏软件 这期想给大家来讲解YOLO这个算法 从零基础学起 并最终学会YOLOV3的Pytorch实现 并学会自己制作数据集进行模型训练 然后用自己训练好的模型进行预测 话不多说 先上我用Vis
  • windows命令行文件中获取bat文件所在目录相关路径

    批处理命令获取当前盘符和当前目录 d0 是当前盘符 cd 是当前目录 可以用echo cd 进行打印测试 以下例子是命令行编译Visual Studio编写的程序 echo off set b cd 将当前目录保存到参数b中 等号前后不要有
  • qrcode 生成二维码的代码

  • CentOs7.5安装JDK1.8详细步骤

    1 先检查系统中有没有自带的JDK 有就卸载 查询命令 rpm qa grep jdk color 卸载命令 rpm e nodeps 软件名称 再次查询检查是否成功 rpm qa grep jdk color 没有提示也没有报错就是操作成
  • 大厂测试工程师面试题总结-三面(附参考答案)

    三面 1 指针常量 常量指针 指针常量 1 指针常量的本质是一个常量 并且使用指针来修饰它 2 通过对const定义 我们可以简单理解为这个指针是个常量 它不可以被修改 即它只能指向开始时我们给赋值的变量 不可以被修改从而再指向其他的变量
  • 安装mmdetection(windows下)

    windows环境安装mmdetection 创建pytorch环境 最终安装的版本信息 安装过程 step1 安装mmcv full step2 安装mmdetection 安装mmdet报错 Could not build wheels
  • Linux进程间通信--msgsnd函数的作用

    msgsnd函数用于将消息发送到消息队列中 它的原型如下 int msgsnd int msqid const void msgp size t msgsz int msgflg 参数解释 msqid 消息队列标识符 由msgget函数返回
  • windows系统查看进程端口号的命令

    查看进程端口号 1 查看windows所有端口进程 netstat ano 命令提示符窗口 2 查询指定的端口占用 netstat aon findstr 端口 显示列表中的PID 然后根据PID在电脑的任务管理器中查看对应的占用程序 根据
  • Python 生成当前项目依赖包 requirements

    Python 生成当前项目依赖包 requirements 1 安装 pipreqs pip install pipreqs 2 执行命令 在当前工程目录生成 pipreqs encoding utf8 force 3 使用requirem
  • CentOS下ELK 7.2生产安全部署

    01 架构说明 在需要采集日志的服务器上部署Filebeat服务 它将采集到的日志数据推送到Kafka集群 Logstash服务通过input插件读取Kafka集群对应主题的数据 期间可以使用filter插件对数据做自定义过滤解析处理 然后
  • Android Studio 4.x 返回上一次编辑的地方

    Android Studio 升级到 4 x 后 返回上一次编辑的地方的快捷键变成了 Alt Shift 左箭头 了
  • JUC之ReentrantReadWriteLock

    JUC之ReentrantReadWriteLock 1 背景 由于ReentrantLock是独占可重入锁 因此在进行操作的时候 不能够满足多线程同时操作数据 为了满足并发场景下的临界资源的数据共享 出现了ReentrantReadWri