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

读写锁简介

ReentrantReadWriteLock

使用场景

当读操作远远高于写操作时,这时候使用 结果 3 3 t0 读写锁 让 读-读 可以并发,提高性能。 类似于数据库中的 from ... lock in share mode

特点

读读可以并发,读写和写写互斥

读锁不支持条件变量

重入时升级不支持:即持有读锁的情况下去获取写锁,会导致获取写锁永久等待

重入时降级支持:即持有写锁的情况下去获取读锁

应用

缓存,保证缓存的读取和数据库保持一致。一般情况下,先更新数据库,再清理缓存;

样例代码

package concurrent;import java.util.concurrent.locks.ReentrantReadWriteLock;class CachedData {Object data;// 是否有效,如果失效,需要重新计算 datavolatile boolean cacheValid;final ReentrantReadWriteLock rwl = new ReentrantReadWriteLock();void processCachedData() {rwl.readLock().lock();if (!cacheValid) {// 获取写锁前必须释放读锁rwl.readLock().unlock();rwl.writeLock().lock();try {// 判断是否有其它线程已经获取了写锁、更新了缓存, 避免重复更新if (!cacheValid) {data = ...cacheValid = true;}// 降级为读锁, 释放写锁, 这样能够让其它线程读取缓存rwl.readLock().lock();} finally {rwl.writeLock().unlock();}}// 自己用完数据, 释放读锁try {use(data);} finally {rwl.readLock().unlock();}}
}

 备注: 

释放读锁和获取写锁之间,怎么能确保没有别的线程获取了写锁?参照这个代码样例。 一般是获取,获取完了之后,再做双重非空判断。非空判断 ---》加锁 ---》非空判断,类似单例模式之中的双重锁写法。

这里的非空判断,可以替换为对voliate修饰的变量的判断,类似于上面代码中的写法

StampedLock

特点

在使用读锁、写锁时都必须配合【戳】使用;先乐观读,如果【戳】变化,代表已经被其他线程更改过了,升级锁。

乐观读,StampedLock 支持 tryOptimisticRead() 方法(乐观读),读取完毕后需要做一次 戳校验 如果校验通过,表示这期间确实没有写操作,数据可以安全使用,如果校验没通过,需要重新获取读锁,保证数据安全。

和ReentrantReadWriteLock对比

StampedLock 不支持条件变量

StampedLock 不支持可重入

样例代码

package concurrent;import lombok.extern.slf4j.Slf4j;import java.util.concurrent.locks.StampedLock;import static util.Sleeper.sleep;@Slf4j(topic = "c.TestStampedLock")
public class TestStampedLock {public static void main(String[] args) {DataContainerStamped dataContainer = new DataContainerStamped(1);new Thread(() -> {dataContainer.read(1);}, "t1").start();sleep(0.5);new Thread(() -> {
//            dataContainer.read(0);dataContainer.write(0);}, "t2").start();}
}@Slf4j(topic = "c.DataContainerStamped")
class DataContainerStamped {private int data;private final StampedLock lock = new StampedLock();public DataContainerStamped(int data) {this.data = data;}public int read(int readTime) {long stamp = lock.tryOptimisticRead();log.debug("optimistic read locking...{}", stamp);sleep(readTime);if (lock.validate(stamp)) {log.debug("read finish...{}, data:{}", stamp, data);return data;}// 锁升级 - 读锁log.debug("updating to read lock... {}", stamp);try {stamp = lock.readLock();log.debug("read lock {}", stamp);sleep(readTime);log.debug("read finish...{}, data:{}", stamp, data);return data;} finally {log.debug("read unlock {}", stamp);lock.unlockRead(stamp);}}public void write(int newData) {long stamp = lock.writeLock();log.debug("write lock {}", stamp);try {sleep(2);this.data = newData;} finally {log.debug("write unlock {}", stamp);lock.unlockWrite(stamp);}}
}

http://www.xdnf.cn/news/5186.html

相关文章:

  • Java——反射
  • DeepSeek致谢腾讯!
  • 热蛋白质组分析(TPP)技术的优劣势探讨
  • EPS三维测图软件
  • CDGP重点知识梳理(82个)
  • 20250509 相对论中的\*\*“无空间”并非真实意义上的虚无,而是时空结构尚未形成\*\*的状态。 仔细解释下这个
  • (undone) MIT6.S081 Lec17 VM for APP 学习笔记
  • LeetCode面试题 17.21 直方图的水量
  • 基于扩展卡尔曼滤波(EKF)目标轨迹算法仿真实例
  • 五一旅游潮涌:数字化如何驱动智慧旅游升级
  • IP协议.
  • GUC并发编程和SpringCloud,二者之间的关系
  • MySQL核心内容【持续更新中】
  • Linux——MySQL基础
  • SSH(安全外壳协议)
  • O2OA(翱途)开发平台系统安全-用户登录IP限制
  • 从RR到RC:解析大厂数据库隔离级别变革的背后逻辑
  • ‌2.4G芯片无晶振方案的技术影响分析
  • istio in action之流量控制与路由
  • 深入理解 Istio v1.25.2
  • 后缀表达式+栈(详解)(c++)
  • 自由学习记录(59)
  • WHAT - Node vs Python 执行速度
  • 如何把win10 wsl的安装目录从c盘迁移到d盘
  • DevExpressWinForms-布局容器之PanelControl
  • Linux服务:Nginx服务重写功能
  • 不同渲染任务,用CPU还是GPU?
  • 什么是项目管理的经营思维本质,怎样将其应用于项目实践
  • 解锁健康养生新境界
  • 【RAG】Milvus、Pinecone、PgVector向量数据库索引参数优化