Java多线程之读写锁ReentrantReadWriteLock类使用

news2024/11/18 20:44:59

在JDK中提供了一种读写锁ReentrantReadWriteLock类,相比ReentrantLock类,使用前者可以加快运行效率。ReentrantLock类是具有完全互斥排他的效果,即同一时间只有一个线程在执行ReentrantLock.lock()方法后面的任务,这样做虽然保证了实例变量的线程安全性,但效率却是非常低下的。所以在某些不需要操作实例变量的方法中,完全可以使用读写锁ReentrantReadWriteLock来提升该方法的代码运行速度。

目录

    • 读写锁简介
    • 一、读读共享
    • 二、写写互斥
    • 三、读写互斥
    • 四、写读互斥

读写锁简介

读写锁表示也有两个锁,一个是读操作相关的锁,也称为共享锁;另一个是写操作相关的锁,也叫排他锁。也就是多个读锁之间不互斥,读锁与写锁互斥,写锁与写锁互斥。在没有线程Thread进行写入操作时,进行读取操作的多个Thread都可以获取读锁,而进行写入操作的Thread只有在获取写锁后才能进行写入操作。即多个Thread可以同时进行读取操作,但是同一时刻只允许一个Thread进行写入操作。


下面我们来看ReentrantReadWriteLock类的使用实例:

一、读读共享

创建一个读写服务类ReadWriteService.java,代码如下:

public class ReadWriteService {
	// 创建读写锁
    private final ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
	// 读方法
    public void read() {
        try {
            try {
                lock.readLock().lock();
                System.out.println("获取读锁" + Thread.currentThread().getName()
                        + "==" + System.currentTimeMillis());
                Thread.sleep(5000);
            } finally {
                lock.readLock().unlock();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

创建两个线程,调用读写服务。代码如下:

线程一

public class Thread1 extends Thread {
    private ReadWriteService readWriteService;

    public Thread1(ReadWriteService readWriteService){
        super();
        this.readWriteService = readWriteService;
    }

    @Override
    public void run() {
        readWriteService.read();
    }
}

线程二

public class Thread2 extends Thread{
    private ReadWriteService readWriteService;

    public Thread2(ReadWriteService readWriteService){
        super();
        this.readWriteService = readWriteService;
    }

    @Override
    public void run() {
        readWriteService.read();
    }
}

启动线程,代码如下:

public class Main {
        public static void main(String[] args) {
            ReadWriteService service = new ReadWriteService();
            Thread1 a = new Thread1(service);
            a.setName("A");
            Thread2 b = new Thread2(service);
            b.setName("B");
            a.start();
            b.start();
        }
}

输出如下:
在这里插入图片描述
从控制台中打印的时间来看,两个线程几乎同时进入lock()方法后面的代码。说明在此使用了lock.readLock()读锁的确可以提高程序运行效率,他允许多个线程同时执行lock()方法后面的代码。

二、写写互斥

改一下读写服务类ReadWriteService.java,代码如下:

public class ReadWriteService {
    private final ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
    public void write() {
        try {
            try {
                lock.writeLock().lock();
                System.out.println("获取写锁" + Thread.currentThread().getName()
                        + "==" + System.currentTimeMillis());
                Thread.sleep(5000);
            } finally {
                lock.writeLock().unlock();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

然后修改一下两个线程中调用ReadWriteService的方法,启动

在这里插入图片描述
从运行结果可以看到使用写锁代码lock.writeLock()的效果就是同一时间只允许一个线程执行lock()方法后面的代码。

三、读写互斥

修改ReadWriteService.java代码

public class ReadWriteService {
    private final ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
    public void read() {
        try {
            try {
                lock.readLock().lock();
                System.out.println("获取读锁" + Thread.currentThread().getName()
                        + "==" + System.currentTimeMillis());
                Thread.sleep(5000);
            } finally {
                lock.readLock().unlock();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    public void write() {
        try {
            try {
                lock.writeLock().lock();
                System.out.println("获取写锁" + Thread.currentThread().getName()
                        + "==" + System.currentTimeMillis());
                Thread.sleep(5000);
            } finally {
                lock.writeLock().unlock();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

两个线程类中线程一调用读方法,线程二调用写方法;
然后修改启动类:

public class Main {
        public static void main(String[] args) {
            ReadWriteService service = new ReadWriteService();
            Thread1 a = new Thread1(service);
            a.setName("A");
            a.start();
            Thread2 b = new Thread2(service);
            b.setName("B");
            b.start();
        }
 }

输出:

在这里插入图片描述
由此可以说明“读写”操作也是互斥的,而且下一个示例说明了“写读”操作也是互斥的。也就是说,只要出现“写操作”的过程,就会是互斥的。

四、写读互斥

ReadWriteService.java代码还是跟读写互的一样,只要修改启动类线程执行顺序;代码如下:

public class Main {
        public static void main(String[] args) {
            ReadWriteService service = new ReadWriteService();
            Thread2 b = new Thread2(service);
            b.setName("B");
            b.start();
            Thread1 a = new Thread1(service);
            a.setName("A");
            a.start();
        }
}

运行结果:

在这里插入图片描述
可以看到“写读”操作也是互斥的。

总结:
ReentrantReadWriteLock类是读写锁,他对于“读写”、“写读”和“写写”都是互斥的;而“读读”是异步的,非互斥的。也就是只要包含写操作,就是互斥的;但是对于读读就是共享的。即多个Thread可以同时进行读取操作,但是同一时刻只允许一个Thread进行写入操作。

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

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

相关文章

【UE4 第一人称射击游戏】40-改变武器的可见性

上一篇:【UE4 第一人称射击游戏】39-“M4A1”武器设置本篇效果:步骤:打开“Weapon_M4A1”,删除带有“AK47”的那个骨架网格体打开事件图表,将“SkeletalMesh1”拖入打开“ThirdPersonCharacter”,在事件图表…

Docker:独具魅力的开源容器引擎

Docker 是一个开源的应用容器引擎,让开发者可以打包他们的应用以及依赖包到一个可移植的镜像中,然后发布到任何流行的 Linux 或 Windows操作系统的机器上,也可以实现虚拟化。容器是完全使用沙箱机制,相互之间不会有任何接口&#…

MATLAB-控制系统模型之间的转换

系统的线性时不变(LTI)模型有传递函数(tf)模型、零极点增益(zpk)模型和状态空间(ss)模型,它们之间可以相互转换。模型之间的转换函数可以分为以下两类。第一类是把其他类型的模型转换为函数表示的模型自身&…

PHP多进程(一)

多进程的作用是一个程序启动多个进程。 一个程序启动起来本应该是一个进程,但它可作为父进程启动多个子进程来一起操作 形成并发操作 pcntl是php官方的多进程扩展,只能在linux环境使用 以下所有操作请在Linux环境下操作: 先认识两个函数,下面是官方文档地址: …

铜缆测试——近端和远端串扰(NEXT和FNEXT)

如果您非常熟悉铜缆测试,那么很可能听说过串扰——一对或一个通道上传输的信号对另外一对或一个通道产生不良影响的现象。(杂讯) 串扰会对具体的一对导线或整根电缆形成干扰,导致误码或数据无法传输。例如,您是否曾经在电话中听到有其他人说话…

马蹄集 数组最大公约数

给定一个由N个正整数组成的数组&#xff0c;求所有数组元素的最大公约数。 格式 输入格式&#xff1a;第一行输入数组长度N,第二行输入数组元素&#xff0c;整型 空格分隔。 输出格式&#xff1a;输出整型 #include <bits/stdc.h> using namespace std;int gcd(int a…

(十八)Java的时间与日期(2)

目录 前言: 一、JDK8新增日期类 二、LocalDate&#xff0c;LocalTime,LocalDateTime 三、Instant时间戳 四、DateTimeFormatter类 五、Duration/Period类 六、ChronoUnit类 前言: JDK 8中增加了一套全新的日期时间API&#xff0c;这套API设计合理&#xff0c;是线程安全的。新的…

ctfshow学习记录-web入门(sql注入191-200)

目录web191web192web193web194web195web196web197web198web199web200九某人来更新啦&#xff1a;2023年第一篇wp新鲜出炉&#xff5e; web191 解答&#xff1a;增加了过滤 过滤了ascii&#xff0c;可以用ord方法代替。&#xff08;这里手册中也有告知~&#xff09; web190的pa…

【数据结构与算法】Trie

&#x1f600;大家好&#xff0c;我是白晨&#xff0c;一个不是很能熬夜&#x1f62b;&#xff0c;但是也想日更的人✈。如果喜欢这篇文章&#xff0c;点个赞&#x1f44d;&#xff0c;关注一下&#x1f440;白晨吧&#xff01;你的支持就是我最大的动力&#xff01;&#x1f4…

集合引用类型 下

目录 Map Map.set() Map.get() Map.delete() Map.has() Map.values() Map.entries() Map.clear() 选择Object 还是Map 数据转换 转为数组 转为 JSON 对象转为 Map 数组转为 Map 转为Object WeakMap 基本API 弱键 不可迭代 Set 创建Set实例 Set实例转数组 si…

STM32-启动文件详解

✅作者简介&#xff1a;嵌入式入坑者&#xff0c;与大家一起加油&#xff0c;希望文章能够帮助各位&#xff01;&#xff01;&#xff01;&#xff01; &#x1f4c3;个人主页&#xff1a;rivencode的个人主页 &#x1f525;系列专栏&#xff1a;玩转FreeRTOS &#x1f4ac;推荐…

python基础篇之数字类型(下)

大家好&#xff0c;我是csdn的博主&#xff1a;lqj_本人 这是我的个人博客主页&#xff1a;lqj_本人的博客_CSDN博客-微信小程序,前端,vue领域博主lqj_本人擅长微信小程序,前端,vue,等方面的知识https://blog.csdn.net/lbcyllqj?spm1000.2115.3001.5343 哔哩哔哩欢迎关注&…

在vue2使用百度脑图的kityminder-core进行二次开发思维导图,在源码中添加新的命令

需求说明&#xff1a;最近在搞kityminder-core的思维导图&#xff0c;需要增加一个给节点添加文件的功能&#xff0c;一直在研究源码&#xff0c;发现都是通过执行命令的方式实现的。一直卡在新增命令的步骤&#xff0c;搞了好多天了今天找到了如何在源码里新增命令&#xff0c…

leetcode 1807. 替换字符串中的括号内容【python3双指针+哈希表】实现过程分析以及思路整理

题目 给你一个字符串s&#xff0c;它包含一些括号对&#xff0c;每个括号中包含一个非空的键。 比方说&#xff0c;字符串"(name)is(age)yearsold"中&#xff0c;有两个括号对&#xff0c;分别包含键"name"和"age"。 你知道许多键对应的值&…

android实现侧边栏:解决header控件无法操作和底部menuitem点击无效的问题

1&#xff1a;目录结构&#xff1a;&#xff08;源码和总结都放在b站&#xff0c;链接在底部&#xff09; 2&#xff1a;实现的大概逻辑&#xff1a; 使用drawerlayout抽屉布局实现&#xff0c;并使用navigationview加载头部和底部 3&#xff1a;核心问题一&#xff1a;header…

用Python来创建7种不同的文件格式

用Python来创建7种不同的文件格式一、用Python来创建7种不同的文件格式1.1、文本文件1.2、CSV文件1.3、Excel文件1.4、压缩文件1.5、XML文件1.6、JSON文件1.7、PDF文件一、用Python来创建7种不同的文件格式 1.1、文本文件 写入 file_name "my_text_file.txt"# 将…

微信小程序——WXML模板语法-条件渲染,列表渲染

一.条件渲染1.wx:if在小程序中&#xff0c;使用wx:if"{{condition}}"来判断是否需要渲染该代码块&#xff1a;也可以用wx:elif和wx:else来添加else判断&#xff1a;实例如下&#xff1a;1.在js文件中定义一个typedata:{type:1 },此时虚拟页面上显示的就是&#xff1a…

二十四、Kubernetes中Deployment(Deploy)控制器详解

1、概述 在kubernetes中&#xff0c;有很多类型的pod控制器&#xff0c;每种都有自己的适合的场景&#xff0c;常见的有下面这些&#xff1a; ReplicationController&#xff1a;比较原始的pod控制器&#xff0c;已经被废弃&#xff0c;由ReplicaSet替代 ReplicaSet&#xff…

kafka/bin/kafka-run-class.sh: line 342: exec: java: not found

本来jps看了下&#xff0c;kafka和zookeeper都起来了&#xff0c;手痒&#xff0c;非要换宝塔的进程守护管理器&#xff0c;选目录为/home/kafka&#xff0c;命令为/home/kafka/bin/zookeeper-server-start.sh /home/kafka/config/zookeeper.properties 就在日志里看到 kafk…

马蹄集 整除的总数

整除的总数 难度&#xff1a;白银 时间限制&#xff1a;1秒 巴占用内存&#xff1a;64M 输入正整数N和M,其中N<M。求区间[N,M]中可被K整除的总数。 格式 输入格式&#xff1a;输入正整数N,M和K,空格分隔。 输出格式&#xff1a;输出整型 #include <bits/stdc.h&g…