一、读写锁

在我的《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. Docker镜像构建之docker commit

    我们可以通过公共仓库拉取镜像使用,但是,有些时候公共仓库拉取的镜像并不符合我们的需求.尽管已经从繁琐的部署工作中解放出来了,但是在实际开发时,我们可能希望镜像包含整个项目的完整环境,在其他机器上拉取打 ...

  2. Altium design使用日常故障总结

    1.altiumdesigner09如何将不同的板子拼在一起发给工厂?打开这两个图,其中一个图ctrl+a,ctrl+c,打开另一个图pastespecial.放置时选取一边对齐.制版时告诉厂家做个V ...

  3. React中Ref 的使用 React-踩坑记_05

    React中Ref 的使用 React v16.6.3 在典型的React数据流中,props是父组件与其子组件交互的唯一方式.要修改子项,请使用new props 重新呈现它.但是,在某些情况下,需 ...

  4. 活字格发布新版本,插件公开,引领Web开发新潮流

    日前,活字格Web 应用生成平台发布V4.0版本,首次公开插件机制,强大的扩展性和系统集成能力,引起业内瞩目. 活字格是由西安葡萄城自主研发的 Web 应用生成平台,提供易用的类Excel可视化设计器 ...

  5. TextView显示html样式的文字

    项目需求: TextView显示一段文字,格式为:白雪公主(姓名,字数不确定)向您发来了2(消息个数,不确定)条消息 这段文字中名字和数字的长度是不确定的,还要求名字和数字各自有各自的颜色. 一开始我 ...

  6. Java中的反射原理以及简单运用(原理+例子)

    @ 目录 学习总结 1. 为什么要使用反射 2. 反射的概念 3. Java反射加载过程 4. 反射优缺点 5. 字节码对象理解 6. 获取字节码对象(.class)的三种方式 7. 反射常用API ...

  7. IO流入门

    @ 目录 总结内容 1. IO流是什么 2. 字符流和字节流 3. File常用API(前面类型为返回类型) 4. 编码转换 5. IO流实现流程 6. 输入输出流简单实现 7. 输入输出流简单实现 ...

  8. 小程序picker的使用

    效果图: 代码: <view class='infoItem'> <view class='infoItem-left'><text style='color:red'& ...

  9. css换算rem单位

    地址:https://www.freetechs.cn/tool/rem2px.html

  10. msyql查看版本号、最大连接数、当前连接数等

    1.查看版本号 select version(); 2.查看最大连接数 show variables like 'max_connections'; 3.查看当前连接数(如果是root帐号,你能看到所 ...