当前位置:网站首页>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); //释放读锁或写锁 } } }
边栏推荐
猜你喜欢
Machine learning model too slow?Look at Intel (R) extension to accelerate
继承关系下构造方法的访问特点:
开源一夏 | 牛plus,多层嵌套动态JSON该如何解析总结
利用图像二维熵实现视频信号丢失检测(Signal Loss Detection)
人大金仓数据库登录、查看数据库
以技术御风险,护航云原生 | 同创永益 X 博云举办产品联合发布会
Apple developer account application process full version
Feign应用及源码剖析
Dubins curve study notes and related thinking
快速定位线上慢 SQL 问题,掌握这几个性能排查工具可助你一臂之力
随机推荐
Classification of software testing
2022世界机器人大会即将举办,智能机器人助推传统行业向智能化、数字化转型升级
「每周译Go」这次我们来点不一样的!--《How to Code in Go》系列上线
移动端/嵌入式-CV模型-2018:MobileFaceNets
Loadrunner12.0.2 installation and Chinese language pack installation (Chinese)
文档数据库是怎么定位一个文档的呀?
Recommend 100 nice English songs
xgboost 加速
在mysql中,存储过程中参数为中文 乱码解决方案
Loadrunner的录制event为0的问题解决方法与思路
A concise tutorial on expanding (increasing capacity) of VMWare Esxi virtual system data storage
业务缓存之体系化设计与开发
NoSQL数据库有哪些优势吗?又有哪些劣势呢?
In the.net core, the use of c # realize fastdfs batch file upload more
Dubins曲线学习笔记及相关思考
Mysql数据库架构介绍
Feign application and source code analysis
关于振弦采集模块及采集仪振弦频率值准确率的问题
牛刀小试基本语法,Go lang1.18入门精炼教程,由白丁入鸿儒,go lang基本语法和变量的使用EP02
移动端/嵌入式-CV模型-2019:MobelNets-v3