一、读写锁

在我的《java并发编程》上一篇文章中为大家介绍了《ReentrantLock读写锁》,ReentrantReadWriteLock可以保证最多同时有一个线程在写数据,或者可以同时有多个线程读数据,但读写不能同时进行。

比如你正在做的是日志,有一个线程正在做写操作,但是在写日志的时候你可能需要把日志集中转移到集中管理日志服务,但是此时读线程不能读数据(因为无法获取读锁)。面对这个需求,ReentrantReadWriteLock显然不是我们的解决方案,我们希望:最多一个线程在进行写操作(加写锁),但是同时允许多个线程进行读操作(加读锁),解决方案是StampedLock。

二、悲观读锁

StampedLock 同样可以实现写锁和读锁的功能,Stamped在英文中有印章的含义,对于StampedLock大家可以这么理解,使用一个印章加锁,必须使用该印章解锁。

public class TestStampedLock {
Map<String,String> map = new HashMap<>();
//锁对象
private StampedLock lock = new StampedLock(); //写操作函数
public void put(String key, String value){
long stamp = lock.writeLock(); //加写锁
try {
map.put(key, value); //写操作
} finally {
lock.unlockWrite(stamp); //释放写锁
}
} public String get(String key) {
long stamp = lock.readLock(); //加读锁
try {
return map.get(key); //读操作
} finally {
lock.unlockRead(stamp); //释放读锁
}
}
}

上文中的读锁readLock,在StampedLock模式中被称为悲观读锁,之所以叫做悲观读锁是和StampedLock支持的另一种模式“乐观读”相对应的。

写锁、悲观读锁的语义和 ReadWriteLock 的写锁、读锁的语义基本是一致的,允许多个线程同时获取悲观读锁,但是只允许一个线程获取写锁,写锁和悲观读锁是互斥的。多线程环境下,写操作的同时不能读。所以到这里为止,StampedLock与ReadWriteLock并没有很大的区别。

三、乐观读

需要注意的是,这里我写的是乐观读,而不是乐观读锁,因为乐观读是不加锁的。通过tryOptimisticRead()函数获取一个stamp,这里的tryOptimisticRead() 就是乐观读,乐观读因为没有加锁,所以读取数据的性能会更高一点。即:已经有写操作线程加锁的同时,仍然允许读操作线程继续进行。

如果你的读写操作有比较强的时间点数据一致性要求,即:同一个时间点读操作读到的数据,一定与该时间点写操作保持数据一致性。那么,你就需要进行validate校验,stamp此时可以理解为一个版本号,如果写操作版本为2,读操作版本为1,说明你读到的数据不是最新的。你需要去读取最新版本的数据(版本号为2),所以需要升级为悲观读锁,代码如下:

public String readWithOptimisticLock(String key) {
long stamp = lock.tryOptimisticRead(); //乐观读
String value = map.get(key); //读取数据 if(!lock.validate(stamp)) { //校验数据是否是最新版本
stamp = lock.readLock(); //如果不是,升级为悲观读锁
try {
return map.get(key);
} finally {
lock.unlock(stamp);
}
}
return value;
}

欢迎关注我的博客,更多精品知识合集

本文转载注明出处(必须带连接,不能只转文字):字母哥博客 - zimug.com

觉得对您有帮助的话,帮我点赞、分享!您的支持是我不竭的创作动力!。另外,笔者最近一段时间输出了如下的精品内容,期待您的关注。

java并发编程-StampedLock高性能读写锁的更多相关文章

  1. Java并发编程笔记之读写锁 ReentrantReadWriteLock 源码分析

    我们知道在解决线程安全问题上使用 ReentrantLock 就可以,但是 ReentrantLock 是独占锁,同时只有一个线程可以获取该锁,而实际情况下会有写少读多的场景,显然 Reentrant ...

  2. Java并发(8)- 读写锁中的性能之王:StampedLock

    在上一篇<你真的懂ReentrantReadWriteLock吗?>中我给大家留了一个引子,一个更高效同时可以避免写饥饿的读写锁---StampedLock.StampedLock实现了不 ...

  3. 多线程高并发编程(4) -- ReentrantReadWriteLock读写锁源码分析

    背景: ReentrantReadWriteLock把锁进行了细化,分为了写锁和读锁,即独占锁和共享锁.独占锁即当前所有线程只有一个可以成功获取到锁对资源进行修改操作,共享锁是可以一起对资源信息进行查 ...

  4. Java并发编程的艺术读后总结

    2019.04.26 - 2019.04.28扫了一遍 Chapter volatile synchronized实现原理 Java内存模型 happen-before 重排序 顺序一致性 JMM 线 ...

  5. Java并发编程:同步锁、读写锁

    之前我们说过线程安全问题可以用锁机制来解决,即线程必要要先获得锁,之后才能进行其他操作.其实在 Java 的 API 中有这样一些锁类可以提供给我们使用,与其他对象作为锁相比,它们具有更强大的功能. ...

  6. 读《Java并发编程的艺术》(一)

    离开博客园很久了,自从找到工作,到现在基本没有再写过博客了.在大学培养起来的写博客的习惯在慢慢的消失殆尽,感觉汗颜.所以现在要开始重新培养起这个习惯,定期写博客不仅是对自己学习知识的一种沉淀,更是在督 ...

  7. Java并发编程笔记之StampedLock锁源码探究

    StampedLock是JUC并发包里面JDK1.8版本新增的一个锁,该锁提供了三种模式的读写控制,当调用获取锁的系列函数的时候,会返回一个long 型的变量,该变量被称为戳记(stamp),这个戳记 ...

  8. 读Java并发编程实践中,向已有线程安全类添加功能--客户端加锁实现示例

    在Java并发编程实践中4.4中提到向客户端加锁的方法.此为验证示例,写的不好,但可以看出结果来. package com.blackbread.test; import java.util.Arra ...

  9. 那些年读过的书《Java并发编程实战》和《Java并发编程的艺术》三、任务执行框架—Executor框架小结

    <Java并发编程实战>和<Java并发编程的艺术>           Executor框架小结 1.在线程中如何执行任务 (1)任务执行目标: 在正常负载情况下,服务器应用 ...

随机推荐

  1. String工具类之“四个判空方式”StringUtils.isNotBlank和StringUtils.isEmpty和StringUtils.isBlank和StringUtils.isNotEmpty

    一.判断str字符串都不为空==>StringUtils.isNotBlank(String str); 1 /** 2 * <p>检查一个字符串是否非空("") ...

  2. solr集群搭建,zookeeper集群管理

    1. 第一步 把solrhome中的配置文件上传到zookeeper集群.使用zookeeper的客户端上传. 客户端命令位置:/root/solr-4.10.3/example/scripts/cl ...

  3. 以太网在汽车行业中的挑战——灵活的接口及软件使ECU开发不再复杂

    以太网在汽车行业中的挑战--灵活的接口及软件使ECU开发不再复杂 以太网将会在一批新车型中作为一个车载系统网络使用.因此,下一步就是以太网和现有汽车网络技术的集成,包括:CAN.FlexRay.LIN ...

  4. 用jq实现移动端滑动轮播以及定时轮播效果

    Html的代码: <div class="carousel_img"> <div class="car_img" style="ba ...

  5. JavaScript 小技巧 数组去重

    const array = [1, 2, 3, 3, 5, 5, 1]; const uniqueArray = [...new Set(array)]; console.log(uniqueArra ...

  6. 最长非降子序列的N*logN解法

    之前讲到过求最长非降子序列的O(N^2)解法. 链接 这次在原来的基础上介绍一下N*logN解法. 该解法主要是维护一个数组minValue,minValue[i]表示最长上身子序列长度为i的数的最小 ...

  7. Django高级之-缓存

    一 缓存介绍 在动态网站中,用户所有的请求,服务器都会去数据库中进行相应的增,删,查,改,渲染模板,执行业务逻辑,最后生成用户看到的页面. 当一个网站的用户访问量很大的时候,每一次的的后台操作,都会消 ...

  8. Java报错:Error creating bean with name 'testController': Injection of resource dependencies failed

    报错如下: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'testCo ...

  9. SSL及GMVPN握手协议详解

    之前写过一篇文章搞懂密码学基础及SSL/TLS协议,主要介绍了加密学的基础,并从整体上对SSL协议做了介绍.由于篇幅原因,SSL握手的详细流程没有深入介绍.本文将拆解握手流程,在消息级别对握手进行详细 ...

  10. AngularJS性能优化心得,自己踩过的抗,及一些别人的经验(转哦)

    脏数据检查 != 轮询检查更新 谈起angular的脏检查机制(dirty-checking), 常见的误解就是认为: ng是定时轮询去检查model是否变更.其实,ng只有在指定事件触发后,才进入$ ...