博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Java读写锁(ReentrantReadWriteLock)学习
阅读量:5216 次
发布时间:2019-06-14

本文共 2730 字,大约阅读时间需要 9 分钟。

什么是读写锁

平时,我们常见的synchronized和Reentrantlock基本上都是排他锁,这些锁在同一时刻只允许一个线程进行访问,哪怕是读操作。而读写锁是维护了一对锁(一个读锁和一个写锁),通过分离读锁和写锁,使得同一时刻可以允许多个读线程访问,但是在写线程进行访问时,所有的读线程和其他写线程均被阻塞。

读写锁的优点

1. 简化了读写交互场景编程的复杂度:

在常见的开发中,我们经常会定义一个共享的用作缓存的数据结构;比如一个大Map,缓存全部的城市Id和城市name对应关系。这个大Map绝大部分时间提供读服务(根据城市Id查询城市名称等);而写操作占有的时间很少,通常是在服务启动时初始化,然后可以每隔一定时间再刷新缓存的数据。但是写操作开始到结束之间,不能再有其他读操作进来,并且写操作完成之后的更新数据需要对后续的读服务可见。

在没有读写锁支持的时候,如果需要完成上述工作就要使用Java的等待通知机制,就是当写操作开始时,所有晚于写操作的读操作均会进入等待状态,只有写操作完成并进行通知之后,所有等待的读操作才能继续执行(多个写操作之间依靠synchronized关键字进行同步),这样做的目的是使读操作能读取到正确的数据,不会出现脏读。改用读写锁实现上述功能,这只需要在读操作时获取读锁,写操作时获取写锁即可。当写锁被获取到时,后续(非当前操作线程)的读写锁都会被阻塞,写锁释放之后,所有操作继续执行,编程方式相对于使用等待通知机制的实现方式而言。变得简单明了。

2.扩大了程序的吞吐量:

读写锁通过读写使用不同的锁,读操作使用共享锁,写操作使用独占锁的形式,让程序能提供更好的并发性和吞吐量。在读多于写的情况下,读写锁能够提供比排它锁更好的性能。

ReentrantReadWriteLock的特性
特性 说明
公平性选择 支持非公平(默认)和公平的锁获取方式,吞吐量还是非公平优于公平
重进入 该锁支持重进入,以读写线程为例:读线程在获取了读锁之后,能够再次获取读锁。而写线程在获取了写锁之后能够再次获取写锁,同时也可以获取读锁
锁降级 允许从写锁降级为读锁,实现方式时:先获取写锁,再获取读锁,最后释放写锁,此时就会将为读锁。但是,从读锁升级到写锁时不可能的
Condition支持 写锁提供了一个Condition实现,对于写锁来说,该实现的行为与ReentrantLock.newCondition()提供的Condition实现对ReentrantLock所做的行为相同。当然,此Condition只能用于写锁。读锁不支持Condition,readLok().newCondition()会抛出UnsupportedOperationException。
监测 这些方法主要用于监听系统状态,而不是同步控制

使用案例

public class ReentrantReadWriteLockTest {    private static Map
map = new HashMap<>(); private static ReentrantReadWriteLock rwl = new ReentrantReadWriteLock(); private static Lock readLock = rwl.readLock(); private static Lock writeLock = rwl.writeLock(); public static void main(String[] args) { ReentrantReadWriteLockTest reentrantReadWriteLockTest = new ReentrantReadWriteLockTest() ; Executor executor = Executors.newFixedThreadPool(4) ; executor.execute(() -> { System.out.println("写锁开始"); reentrantReadWriteLockTest.put("1","1") ; System.out.println("写锁结束"); }); executor.execute(() -> { System.out.println("读锁开始"); System.out.println(reentrantReadWriteLockTest.get("4")); System.out.println("读锁结束"); }); executor.execute(() -> { System.out.println("写锁开始"); reentrantReadWriteLockTest.put("3", "3") ; System.out.println("写锁开始"); }); executor.execute(() -> { System.out.println(reentrantReadWriteLockTest.get("1")); }); } public void put(String key , String value) { try { writeLock.lock(); map.put(key, value); }finally { writeLock.unlock(); } } public Object get(String key) { try { readLock.lock(); return map.get(key); }finally { readLock.unlock(); } }}

转载于:https://www.cnblogs.com/boothsun/p/7880949.html

你可能感兴趣的文章
session token两种登陆方式
查看>>
C# ArrayList
查看>>
IntelliJ IDEA 12集成Tomcat 运行Web项目
查看>>
java,多线程实现
查看>>
个人作业4-alpha阶段个人总结
查看>>
android smack MultiUserChat.getHostedRooms( NullPointerException)
查看>>
递归-下楼梯
查看>>
实用的VMware虚拟机使用技巧十一例
查看>>
监控工具之---Prometheus 安装详解(三)
查看>>
Azure Iaas基础之---创建虚拟机
查看>>
不错的MVC文章
查看>>
网络管理相关函数
查看>>
IOS Google语音识别更新啦!!!
查看>>
20190422 T-SQL 触发器
查看>>
[置顶] Linux终端中使用上一命令减少键盘输入
查看>>
poj1422_有向图最小路径覆盖数
查看>>
BootScrap
查看>>
[大牛翻译系列]Hadoop(16)MapReduce 性能调优:优化数据序列化
查看>>
WEB_点击一百万次
查看>>
CodeForces - 878A Short Program(位运算)
查看>>