当前位置:网站首页>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); //释放读锁或写锁 } } }边栏推荐
猜你喜欢
随机推荐
Service Mesh迁移原则
FreeSql 将 Saas 租户方案精简到极致[.NET ORM SAAS]
In ASP.NET Core 2.0, solve the configuration problem of large file upload
使用文档数据库的目的是什么呢?
String equals hashcode
MySQL学习第一部分:认识MySQL
苹果开发者账号申请流程完整版
Web优化躬行记(6)——优化闭环实践
PHP 手机号脱敏,正则表达式/简易版
使用类似搭积木的低代码开发方式进行 SAP API 开发
移动端/嵌入式-CV模型-2018:MobileFaceNets
一个用来装逼的利器
Classification of software testing
新款“廉价”SUV曝光,安全、舒适一个不落
机器学习模型太慢?来看看英特尔(R) 扩展加速
列存储数据库是什么呢?
2.5W 字详解线程与锁了,面试随便问!!
实战项目:瑞吉外卖开发笔记
键值数据库中可以对值进行查询嘛?
语音聊天app开发——对用户更具吸引力的设计









