从synchronized到ReentrantLock,从ReentrantLock到ReentrantReadWriteLock,都在尽量减少锁带来的负面影响。

  · synchronized:语言级别支持,使用简单,但缺少灵活性,且不可中断。

  · ReentrantLock:JUC提供,使用相对复杂,但是可灵活控制锁的获得和释放,可中断。

  · ReentrantReadWriteLock:实现了锁的分离,分为读锁和写锁,写写、写读互斥,读读可并发使用。

  虽然synchronized、ReentrantLock、ReentrantReadWriteLock已经提供相对丰富的解决方案来供锁的使用,但这些锁在宏观来看的话,都属于悲观锁。ReentrantReadWriteLock进行了锁的分离,但读锁和写锁之间的获取依然是悲观的,在读多写少的极限情况下,写锁可能出现永远无法获得锁的情况。

  JDK1.8引入了StampedLock,StampedLock提供了三种锁模式:

  · 写锁:写锁是一个独占锁,属于悲观锁。

  · 读锁:读锁是一个共享锁,当和写锁出现竞争时,若当前已获取读锁,禁止写入,属于悲观锁。

  · 乐观读锁:乐观读锁乐观地估计读的过程中大概率不会有写入,因此被称为乐观读锁。读取完成后,会进行版本号的校验,若读取过程中发生写入,则重新读取。

  演示示例:

  读锁与写锁:

  读锁与写锁之间是互斥的,读锁被线程持有时,为了防止出现类似脏读问题,其它线程是无法获取写锁的,只有读锁没有线程持有时,写锁才可以被获取。

  首先,新建一个读取线程类和一个写入线程类,用于模拟多线程环境:

package com.securitit.serialize.locks;import java.util.List;
import java.util.concurrent.locks.StampedLock;public class StampedReadLockThread extends Thread {// 锁实例.private StampedLock lock;// 模拟数据存储.private List<String> dataList;// 构造方法.public StampedReadLockThread(StampedLock lock, List<String> dataList) {this.lock = lock;this.dataList = dataList;}@Overridepublic void run() {long stamped = -1;try {stamped = lock.readLock();System.out.println(Thread.currentThread().getName() + ":读锁获得锁.");for (String data : dataList) {System.out.println(Thread.currentThread().getName() + ":读锁读数据.");}Thread.sleep(2000);} catch (Exception ex) {ex.printStackTrace();} finally {System.out.println(Thread.currentThread().getName() + ":读锁释放锁.");lock.unlockRead(stamped);}}}
package com.securitit.serialize.locks;import java.util.List;
import java.util.concurrent.locks.StampedLock;public class StampedWriteLockThread extends Thread {// 锁实例.private StampedLock lock;// 模拟数据存储.private List<String> dataList;// 构造方法.public StampedWriteLockThread(StampedLock lock, List<String> dataList) {this.lock = lock;this.dataList = dataList;}@Overridepublic void run() {long stamped = -1;try {stamped = lock.writeLock();System.out.println(Thread.currentThread().getName() + ":写锁获得锁.");dataList.add("写锁写入数据");Thread.sleep(2000);} catch (Exception ex) {ex.printStackTrace();} finally {System.out.println(Thread.currentThread().getName() + ":写锁释放锁.");lock.unlockWrite(stamped);}}}

  在测试类中逐个调用读取和写入线程:

package com.securitit.serialize.locks;import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.locks.StampedLock;public class StampedLockTester {// StampedLock实例.private static StampedLock lock = new StampedLock();// 模拟数据存储.private static List<String> dataList = new ArrayList<String>();public static void main(String[] args) {new StampedReadLockThread(lock, dataList).start();new StampedWriteLockThread(lock, dataList).start();new StampedReadLockThread(lock, dataList).start();new StampedWriteLockThread(lock, dataList).start();}}

  输出结果:

Thread-0:读锁获得锁.
Thread-2:读锁获得锁.
Thread-0:读锁释放锁.
Thread-2:读锁释放锁.
Thread-3:写锁获得锁.
Thread-3:写锁释放锁.
Thread-1:写锁获得锁.
Thread-1:写锁释放锁.

  无论运行几次,上面的结果读锁获取和释放、写锁获取和释放都是成对出现的,说明读锁和写锁不存在交叉操作。

  乐观读锁与写锁:

  乐观读锁不会阻塞写锁的获取和释放,乐观读锁获取成功后,可以通过validate(stamped)来验证读锁持有过程中是否有写入发生。

  首先,新建一个乐观读取线程类和一个写入线程类,用于模拟多线程环境:

package com.securitit.serialize.locks;import java.util.List;
import java.util.concurrent.locks.StampedLock;public class StampedOptimisticReadLockThread extends Thread {// 锁实例.private StampedLock lock;// 模拟数据存储.private List<String> dataList;// 构造方法.public StampedOptimisticReadLockThread(StampedLock lock, List<String> dataList) {this.lock = lock;this.dataList = dataList;}@Overridepublic void run() {long stamped = -1;try {stamped = lock.tryOptimisticRead();System.out.println(Thread.currentThread().getName() + ":乐观读锁获得锁.");for (String data : dataList) {Thread.sleep(500);System.out.println(Thread.currentThread().getName() + ":乐观读锁读数据.");}if (!lock.validate(stamped)) {stamped = lock.readLock();System.out.println(Thread.currentThread().getName() + ":读锁获得锁.");for (String data : dataList) {Thread.sleep(500);System.out.println(Thread.currentThread().getName() + ":读锁读数据.");}}} catch (Exception ex) {ex.printStackTrace();} finally {System.out.println(Thread.currentThread().getName() + ":乐观读锁释放锁.");lock.unlockRead(stamped);}}}
package com.securitit.serialize.locks;import java.util.List;
import java.util.concurrent.locks.StampedLock;public class StampedWriteLockThread extends Thread {// 锁实例.private StampedLock lock;// 模拟数据存储.private List<String> dataList;// 构造方法.public StampedWriteLockThread(StampedLock lock, List<String> dataList) {this.lock = lock;this.dataList = dataList;}@Overridepublic void run() {long stamped = -1;try {stamped = lock.writeLock();System.out.println(Thread.currentThread().getName() + ":写锁获得锁.");dataList.add("写锁写入数据");Thread.sleep(2000);} catch (Exception ex) {ex.printStackTrace();} finally {System.out.println(Thread.currentThread().getName() + ":写锁释放锁.");lock.unlockWrite(stamped);}}}

  在测试类中逐个调用读取和写入线程:

package com.securitit.serialize.locks;import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.locks.StampedLock;public class StampedLockTester {// StampedLock实例.private static StampedLock lock = new StampedLock();// 模拟数据存储.private static List<String> dataList = new ArrayList<String>();public static void main(String[] args) {new StampedOptimisticReadLockThread(lock, dataList).start();new StampedWriteLockThread(lock, dataList).start();new StampedOptimisticReadLockThread(lock, dataList).start();new StampedWriteLockThread(lock, dataList).start();}}

  输出结果:

Thread-0:乐观读锁获得锁.
Thread-1:写锁获得锁.
Thread-2:乐观读锁获得锁.
Thread-2:乐观读锁读数据.
Thread-1:写锁释放锁.
Thread-3:写锁获得锁.
Thread-3:写锁释放锁.
Thread-0:读锁获得锁.
Thread-2:读锁获得锁.
Thread-0:读锁读数据.
Thread-2:读锁读数据.
Thread-2:读锁读数据.
Thread-0:读锁读数据.
Thread-0:乐观读锁释放锁.
Thread-2:乐观读锁释放锁.

  通过上面输出结果可以看出,使用乐观读锁时,不会限制写锁获取和释放,但乐观读锁进行validate验证时,可能验证失败的结果,此时有两种选择:一是重新获取乐观读锁进行数据操作;二是获取读锁进行数据操作;频繁发生validate验证失败的可能会浪费CPU资源。一般情况下,首先获取乐观读锁尝试进行读取,若验证失败,则获取读锁进行读取。

StampedLock 应用及原理详解相关推荐

  1. CRF(条件随机场)与Viterbi(维特比)算法原理详解

    摘自:https://mp.weixin.qq.com/s/GXbFxlExDtjtQe-OPwfokA https://www.cnblogs.com/zhibei/p/9391014.html C ...

  2. LVS原理详解(3种工作方式8种调度算法)--老男孩

    一.LVS原理详解(4种工作方式8种调度算法) 集群简介 集群就是一组独立的计算机,协同工作,对外提供服务.对客户端来说像是一台服务器提供服务. LVS在企业架构中的位置: 以上的架构只是众多企业里面 ...

  3. jQuery中getJSON跨域原理详解

    详见:http://blog.yemou.net/article/query/info/tytfjhfascvhzxcytp28 jQuery中getJSON跨域原理详解 前几天我再开发一个叫 河蟹工 ...

  4. nginx配置文件及工作原理详解

    nginx配置文件及工作原理详解 1 nginx配置文件的结构 2 nginx工作原理 1 nginx配置文件的结构 1)以下是nginx配置文件默认的主要内容: #user nobody; #配置用 ...

  5. EMD算法之Hilbert-Huang Transform原理详解和案例分析

    目录 Hilbert-Huang Transform 希尔伯特-黄变换 Section I 人物简介 Section II Hilbert-Huang的应用领域 Section III Hilbert ...

  6. 图像质量损失函数SSIM Loss的原理详解和代码具体实现

    本文转自微信公众号SIGAI 文章PDF见: http://www.tensorinfinity.com/paper_164.html http://www.360doc.com/content/19 ...

  7. 深入剖析Redis系列(三) - Redis集群模式搭建与原理详解

    前言 在 Redis 3.0 之前,使用 哨兵(sentinel)机制来监控各个节点之间的状态.Redis Cluster 是 Redis 的 分布式解决方案,在 3.0 版本正式推出,有效地解决了 ...

  8. 【Android架构师java原理详解】二;反射原理及动态代理模式

    前言: 本篇为Android架构师java原理专题二:反射原理及动态代理模式 大公司面试都要求我们有扎实的Java语言基础.而很多Android开发朋友这一块并不是很熟练,甚至半路初级底子很薄,这给我 ...

  9. SVM分类器原理详解

    SVM分类器原理详解 标签: svm文本分类java 2015-08-21 11:51 2399人阅读 评论(0) 收藏 举报  分类: 数据挖掘 文本处理(16)  机器学习 分类算法(10)  目 ...

最新文章

  1. 西安java招聘_西安招聘 | 陕西安控科技公司招聘(员工宿舍、节日福利、餐补)...
  2. efcore多表查询出错_如何提高sql查询的效率?
  3. 今天开始学模式识别与机器学习Pattern Recognition and Machine Learning 书,章节1.1,多项式曲线拟合(Polynomial Curve Fitting)
  4. Dapr微服务应用开发系列2:Hello World与SDK初接触
  5. 牛客题霸 [三个数的最大乘积]C++题解/答案
  6. java学习(99):车站卖票问题
  7. uvm_reg_defines——寄存器模型(四)
  8. springboot注释详解
  9. python官网下载文件-使用Python下载文件的简单示例
  10. 第二阶段冲刺之站立会议1
  11. ASP.NET MVC 3和Razor中的@helper 语法
  12. 转移服务器显示乱码,两台服务器之间数据传输乱码问题
  13. Uva 12563 - Jin Ge Jin Qu(01背包)
  14. 计算机mac地址设置路由器,路由器mac地址怎么设置
  15. 【蓝桥杯集训100题】scratch辨别质数合数 蓝桥杯scratch比赛专项预测编程题 集训模拟练习题第15题
  16. 等比缩放公式_PHP图像等比缩放代码
  17. 加州大学4.8万人大罢工!博士竟卖血为生,多校濒临崩溃!
  18. pyqt5登录界面设计——模仿qq登录界面,可登录注册(数据库)
  19. 如何用ghost备份linux,Linux如何用Ghost备份Linux系统?
  20. 2021SC@SDUSC山东大学软件学院软件工程应用与实践--YOLOV5代码分析(四)general.py-2

热门文章

  1. 统一旗下被遗忘的“奶茶之王”,居然还在闷声发财?
  2. Git基本操作(8)- git 本地仓库回退详解
  3. linux 查看硬盘的uuid_linux下硬盘uuid查看及修改
  4. 四个常用的最短路算法及其细节和应用
  5. IQueryable 和 IEnumable
  6. abap alv中设置数量(QUAN)字段输出时不要有小数位
  7. RK3326 修改 selinux 属性为Permissive
  8. Docker 国内镜像源设置
  9. Android 10.0 关机对话框UI定制化开发(二)
  10. 在北京的外地车限行限号是怎么规定的,外阜进京车辆限制政策