当前位置:网站首页>ReentrantReadWriteLock读写锁和票据锁StempedLock
ReentrantReadWriteLock读写锁和票据锁StempedLock
2022-08-08 10:15:00 【华为云】
ReentrantReadWriteLock读写锁
在没有任何读写锁的时候才可以取得写入锁(悲观读取,容易写线程饥饿),也就是说如果一直存在读操作,那么写锁一直在等待没有读的情况出现,这样我的写锁就永远也获取不到,就会造成等待获取写锁的线程饥饿。平时使用的场景并不多。读写锁维护了一对锁,一个读锁和一个写锁,通过分离读锁和写,使得并发性相比一般的排他锁有了很大提升。
private final Map<String, Data> map = new TreeMap<>(); private final ReentrantReadWriteLock lock = new ReentrantReadWriteLock(); private final Lock readLock = lock.readLock(); private final Lock writeLock = lock.writeLock(); public Data get(String key) { //读操作 加入写锁 readLock.lock(); try { return map.get(key); } finally { readLock.unlock(); } } public Set<String> getAllKeys() { //读操作 加入写锁 readLock.lock(); try { return map.keySet(); } finally { readLock.unlock(); } } public Data put(String key, Data value) { //写操作 加入写锁 writeLock.lock(); try { return map.put(key, value); } finally { readLock.unlock(); } } class Data { }
票据锁:StempedLock
它控制锁有三种模式(写、读、乐观读)。一个StempedLock的状态是由版本和模式两个部分组成。锁获取方法返回一个数字作为票据(stamp),他用相应的锁状态表示并控制相关的访问。数字0表示没有写锁被锁写访问,在读锁上分为悲观锁和乐观锁。乐观读: 如果读的操作很多写的很少,我们可以乐观的认为读的操作与写的操作同时发生的情况很少,因此不悲观的使用完全的读取锁定。程序可以查看读取资料之后是否遭到写入资料的变更,再采取之后的措施。
//定义一个StampedLockprivate final static StampedLock lock = new StampedLock();//操作前加锁long stamp = lock.writeLock();try { count++;} catch (Exception e) {} finally { //操作后在finally中关闭锁,确保锁成功释放,避免死锁 lock.unlock(stamp);}
源码分析
class Point { private double x, y; private final StampedLock sl = new StampedLock(); void move(double deltaX, double deltaY) { // an exclusively locked method long stamp = sl.writeLock(); try { x += deltaX; y += deltaY; } finally { sl.unlockWrite(stamp); } } //下面看看乐观读锁案例 double distanceFromOrigin() { // A read-only method long stamp = sl.tryOptimisticRead(); //获得一个乐观读锁 double currentX = x, currentY = y; //将两个字段读入本地局部变量 if (!sl.validate(stamp)) { //检查发出乐观读锁后同时是否有其他写锁发生? stamp = sl.readLock(); //如果没有,我们再次获得一个读悲观锁 try { currentX = x; // 将两个字段读入本地局部变量 currentY = y; // 将两个字段读入本地局部变量 } finally { sl.unlockRead(stamp); } } return Math.sqrt(currentX * currentX + currentY * currentY); } //下面是悲观读锁案例 void moveIfAtOrigin(double newX, double newY) { // upgrade // Could instead start with optimistic, not read mode long stamp = sl.readLock(); try { while (x == 0.0 && y == 0.0) { //循环,检查当前状态是否符合 long ws = sl.tryConvertToWriteLock(stamp); //将读锁转为写锁 if (ws != 0L) { //这是确认转为写锁是否成功 stamp = ws; //如果成功 替换票据 x = newX; //进行状态改变 y = newY; //进行状态改变 break; } else { //如果不能成功转换为写锁 sl.unlockRead(stamp); //我们显式释放读锁 stamp = sl.writeLock(); //显式直接进行写锁 然后再通过循环再试 } } } finally { sl.unlock(stamp); //释放读锁或写锁 } } }
边栏推荐
猜你喜欢
随机推荐
有哪些典型的列存储数据库呢?
分门别类输入输出,Go lang1.18入门精炼教程,由白丁入鸿儒,go lang基本数据类型和输入输出EP03
软考证书含金量
在.net core中,利用C#实现fastdfs多文件批量上传
.net开发中,C# DateTime.Now 取出的时间含有星期解决办法
"Weekly Translate Go" This time we have something different!-- "How to Code in Go" series launched
snmptrapd+snmptt接收告警并用py脚本发送
A small test of basic grammar, Go lang1.18 introductory refining tutorial, from Bai Ding to Hongru, basic grammar of go lang and the use of variables EP02
什么是本质安全?
2022世界机器人大会即将举办,智能机器人助推传统行业向智能化、数字化转型升级
VPP源地址NAT
新款“廉价”SUV曝光,安全、舒适一个不落
嵌入式C编程中错误异常该如何统一处理?
NoSQL数据库有哪些优势吗?又有哪些劣势呢?
苹果开发者账号申请流程完整版
以技术御风险,护航云原生 | 同创永益 X 博云举办产品联合发布会
Vulnhub靶机:GEMINI INC_ 1
文档数据库中的文档有什么用呢?
使用类似搭积木的低代码开发方式进行 SAP API 开发
PWA 应用 Service Worker 缓存的一些可选策略和使用场景