当前位置: 首页 > news >正文

JUC:读写锁

无锁 => 独占锁 => 读写锁 => 邮戳锁

ReentrantLock, ReentrantReadWriteLock, StampedLock

4.12.1 面试题

  • Java有哪些锁?
  • 对于读写锁,锁饥饿问题是什么?
  • 有没有比读写锁更快的锁?邮戳锁
  • StampedLock知道码?(邮戳锁/票据锁)
  • ReentrantReadWriteLock的锁降级机制是什么?

4.12.2 ReentrantReadWriteLock

读写锁的定义:一个资源能够被多个读线程访问,或者被一个写线程访问,但是不能同时存在读写线程。

class MyResource{Map<String,String> map = new HashMap<>();// Lock lock = new ReentrantLock();ReadWriteLock readWriteLock = new ReentrantReadWriteLock();public void write(String key, String value) throws InterruptedException {// lock.lock();readWriteLock.writeLock().lock();try {System.out.println("正在写入");map.put(key, value);TimeUnit.MILLISECONDS.sleep(50);System.out.println("完成写入");}finally {//lock.unlock();readWriteLock.writeLock().unlock();}}public void read(String key) throws InterruptedException {//lock.lock();readWriteLock.readLock().lock();try {System.out.println("正在读取");map.get(key);TimeUnit.MILLISECONDS.sleep(5000);System.out.println("完成读取");}finally {//lock.unlock();readWriteLock.readLock().unlock();}}

ReentrantReadWriteLock锁降级:将写锁降级为读锁,反之叫锁升级

  • 一个线程锁降级流程
    • 获取
    • 获取
    • 释放

如果先获取读锁,并且没有释放时,线程是无法获取写锁的。因此ReentrantReadWriteLock无法完成锁升级

ReadWriteLock readWriteLock = new ReentrantReadWriteLock();readWriteLock.writeLock().lock(); // 1. 获取写锁
// 写锁状态
readWriteLock.readLock().lock(); // 2. 获取读锁
readWriteLock.writeLock().unlock();// 3. 释放写锁// 锁降级之后为读锁状态readWriteLock.readLock().unlock(); 

统一线程先获取写锁再去获取读锁,相当于重入。

4.12.3 StampedLock

  • 定义
    • StampedLock是JDK1.8新增的一个读写锁,是对ReentrantReadWriteLock的优化。
    • 邮戳锁, 也成为票据锁
    • stamp(戳记,long类型):代表了锁的状态。当stamp返回0时,表示线程获取锁失败,并且,当释放锁或者转换锁时,都要传入最初获取的stamp值。
  • 作用
    • 解决锁饥饿:对于短的只读代码块,使用乐观模式通常可以减少争用并提高吞吐量。
    • 锁降

锁饥饿案例:假如当前有1000个线程,999个在进行读操作,1个在进行写操作。有可能999个读操作长期获取锁,导致1个写操作长时间获取不到锁。导致锁饥饿

ReentrantReadWriteLock 和 StampedLock对比:

ReentrantReadWVriteLock

  • 允许多个线程同时读,但是只允许一个线程写,在线程获取到写锁的时候,其他写操作和读操作都会处于阻塞状态。

  • 读锁和写锁也是互斥的,所以在读的时候是不允许写的,读写锁比传统的synchronized速度要快很多,原因就是在于ReentrantReadWriteLock文持读并发,读读可以共享

StampedLock

  • ReentrantReadWriteLock的读锁被占用的时候,其他线程尝武获取写锁的时候会被阻塞。
  • 但是,StampedLock采取乐观获取锁后,其他线程尝试获取写锁时不会被阳塞,这其实是对读锁的优化,所以,在获取乐观读锁后,还需要对结果进行校验。

对于短的只读代码块,使用乐观模式通常可以减少争用并提高吞吐量。

(1)特点

  • 所有获取锁的方法,都返回一个邮戳StampStamp为零表示获取失败,其余都表示成功;

  • 所有释放锁的方法都需要一个邮戳Stamp,这个Stamp必须是和成功获取锁时得到的Stamp一致;

  • StampedLock是不可重入的,危险 !!!(如果一个线程已经持有了写锁,再去获取写锁的话就会造成死锁)

  • StampedLock有三种访问模式

    • Reading(悲观读模式):和ReentrantReadWriteLock.readLock().lock()一样
    • Writing(悲观写模式):和ReentrantReadWriteLock.writeLock().lock()一样
    • Optimistic Reading(乐观读模式): 无锁机制,类似于数据库中的乐观锁,支持读写并发,乐观认为读取时没有人修改,如果被修改再升级为悲观读模式

乐观读模式:仅当锁定当前未处于写入模式时,方法tryOptimisticead()才返回非零戳记。如果自获得给定标记以来未在写入模式下获取锁定,则方法validate(long)返回tue。这种模式可以被认为是读锁的极弱版本,可以随时被作者,坏。对短的只读代码段使用乐观模式通常可以减少争,用并提高吞吐量。但是,它的使用本质上是脆弱的。乐观读取部分应该只读取字段并将它们保存在局部变量中,以便以后在验证后使用。在乐观摸式下读取的字段可能非常不一致,因此仅在您熟采数据表示以拾查一致性和/或重复调用方法validate()。例如,在首次读取对象或数组引用,然后访问其中一个字段,元素或方法时,通常需要执行此类步。

(2)代码演示

// writelong writeStamp = stampedLock.writeLock();
//业务代码
stampedLock.unlock(writeStamp);// read
long readStamp = stampedLock.readLock();
stampedLock.unlock(writeStamp);
  • 普通读写
public void write(){long stamp = stampedLock.writeLock();System.out.println("WW 写线程准备修改");try{num = num + 1;}finally {stampedLock.unlockWrite(stamp);}System.out.println("WW 写线程修改结束");
}/*** 悲观读*/
public void read(){long stamp = stampedLock.readLock();System.out.println("RR 读线程准备读取");try {TimeUnit.SECONDS.sleep(2);} catch (InterruptedException e) {throw new RuntimeException(e);}try {System.out.println("读线程读取" + num);}finally {stampedLock.unlockRead(stamp);}System.out.println("RR 读线程完成读取");
}
  • 乐观读
/*** 乐观读*/
public void optimisticRead(){long stamp = stampedLock.tryOptimisticRead();int result = num;//故意间隔4秒 乐观认为读取中没有其他线程修改过number值,具体靠判断System.out.println("4s前stampedLock.validate方法(true无修改,false有修改): " + stampedLock.validate(stamp));for (int i = 0; i < 4; i++) {try {TimeUnit.SECONDS.sleep(1);} catch (InterruptedException e) {throw new RuntimeException(e);}System.out.println("OR 正在读取 " + i + "::" + num);System.out.println("OR STAMP Validate标记:" + stampedLock.validate(stamp));}if (!stampedLock.validate(stamp)) { // 有写操作,可以对其进行手动升级System.out.println("有人修改");long readStamp = stampedLock.readLock();try{System.out.println("OR RR 升级悲观读");result = num;System.out.println("OR RR 悲观读后 result " + result);}finally {stampedLock.unlockRead(readStamp);}}System.out.println("OR 最终值 " + result);
}

(3)缺点

  • StampedLock不支持重入,没有Reentrant开头。读写锁原理上都不是可重入锁 ,读锁是伪重入,需要多次释放
  • StampedLock的悲观读锁和写锁都不支持条件变量(Condition),
  • 使用StampedLock一定不要调用中断操作,即不要调用interrupt()方法。
http://www.sczhlp.com/news/154782/

相关文章:

  • 2025 年舞台厂家 TOP 品牌企业权威推荐榜单,铝合金舞台、活动舞台、快装舞台、舞台架、折叠舞台、演出舞台、演唱会舞台桁架、舞台设计公司推荐
  • 资源下载类网站如何做外链网络营销与直播电商就业前景
  • 网站开发前端制作WordPress仿百家号主题
  • 旅游景点网站模板品牌网站建设价位
  • 做问卷调查赚钱的网站网站的建设目标有哪些
  • 沈阳网站备案东莞加盟网站建设
  • 汕头市网站建设分站服务机构珠海网站建设网络公司
  • 广州网站建设亅新科送推广公司网站续费帐怎么做
  • 网站访问很慢做冲压件加工有什么好网站
  • 网站开发流行酷家乐在线家装设计
  • 做最好的言情网站360网站推广官网授权商
  • 网站建议公司怎么建立视频网站
  • 龙华附近网站建设wordpress搭建官网步骤
  • 网站建设如何增加流量网站如何做水晶按钮
  • 梅州市网站制作贵阳餐饮网站建设
  • 网站建设工作总结培训在哪能学到网站建设专业
  • 展架设计在哪个网站做网站建设与管期末试题
  • 专门 做鞋子团购的网站有哪些珠海网站品牌设计公司哪家好
  • 搬家公司怎么做网站电商平面ui设计是什么
  • 网站开发案例详解pdf如何建设自己的摄影网站
  • 网站 关键词wordpress code theme
  • apache怎么配置网站湖南常德天气
  • 舟山市规划建设局网站互联网app开发
  • c 语言可以做网站吗网站开发浏览器分辨率
  • 陕西做教学成果网站的公司网站建设收费标准如何
  • 2025 年钢球厂家 TOP 企业品牌推荐排行榜,轴承 / 碳 / 精密 / 汽配 / 440C 不锈钢球 / 420 不锈钢球 / 304 不锈钢球 / 316L 不锈钢球制造商推荐这十家公司!
  • 2025 年橡胶软接头厂家 TOP 企业品牌推荐排行榜,法兰 / 可曲挠 / 挠性 / KXT / 耐油 / EPDM / 耐腐蚀 / 三元乙丙橡胶软接头 / 橡胶柔性软接头公司推荐!
  • 2025 年低代码平台厂商 TOP 权威推荐排行榜:深度洞察低代码平台行业实力与创新优势
  • 2025 聚焦人力资源管理系统厂商 TOP 推荐排行榜单,洞察人力资源管理系统前沿技术与服务实力!
  • 为什么网站打开老是提示建设中搜一下百度