StampedLock介绍

StampedLock是为了优化可重入读写锁性能的一个锁实现工具,jdk8开始引入

相比于普通的ReentranReadWriteLock主要多了一种乐观读的功能

在API上增加了stamp的入参和返回值

不支持重入

StampedLock如何使用和使用价值

我看了上面的介绍仍然对StampedLock一头雾水,下面我们来揭开StampedLock神秘的面纱

1、对于悲观读和悲观写的方法与ReentranReadWriteLock读写锁效果一样

下面是StampedLock的悲观读、写锁的实现

static ExecutorService service = Executors.newFixedThreadPool();
static StampedLock lock = new StampedLock();
static long milli = ;
static int count = ;

private static long writeLock() {
  long stamp = lock.writeLock(); //获取排他写锁
  count+=1;
  lock.unlockWrite(stamp); //释放写锁
  System.out.println("数据写入完成");
  return System.currentTimeMillis();
}

    private static void readLock() {//悲观读锁
service.submit(() -> {
int currentCount = ;
long stamp = lock.readLock(); //获取悲观读锁
try {
currentCount = count; //获取变量值
try {
TimeUnit.MILLISECONDS.sleep(milli);//模拟读取需要花费20秒
} catch (InterruptedException e) {
e.printStackTrace();
}
} finally {
lock.unlockRead(stamp); //释放读锁
}
System.out.println("readLock==" + currentCount); //显示最新的变量值
});
try {
TimeUnit.MILLISECONDS.sleep();//要等一等读锁先获得
} catch (InterruptedException e) {
e.printStackTrace();
}
}

测试一下效果:

public static void main(String[] args) {
  long l1 = System.currentTimeMillis();
  readLock();  long l2 = writeLock();
  System.out.println(l2-l1);
}

因为我对悲观读操作进行了5秒的数据读取延迟,所以写操作要等5秒后读锁释放才能写入数据

输出结果:

数据写入完成的时间比获取读锁晚5043ms

读到的数据仍然是写入前的0

2、对于乐观读(如果没有进入写模式)可以减少一次读锁的性能消耗,并且不会阻塞写入的操作

我们添加了一个乐观读的方法,这个方法仍然模拟读取延迟5秒,乐观读实现需要参考下面的编程模式(获取乐观锁、校验是否进入写模式)

    private static void optimisticRead() {
service.submit(() -> {
long stamp = lock.tryOptimisticRead(); //尝试获取乐观读锁
int currentCount = count; //获取变量值
if (!lock.validate(stamp)) { //判断count是否进入写模式
stamp = lock.readLock(); //已经进入写模式,没办法只能老老实实的获取读锁
try {
currentCount = count; //成功获取到读锁,并重新获取最新的变量值
} finally {
lock.unlockRead(stamp); //释放读锁
}
}
try {
TimeUnit.MILLISECONDS.sleep(milli);//模拟读取需要花费20秒
} catch (InterruptedException e) {
e.printStackTrace();
}
//走到这里,说明count还没有被写,那么可以不用加读锁,减少了读锁的开销
System.out.println("optimisticRead==" + currentCount); //显示最新的变量值
});
try {
TimeUnit.MILLISECONDS.sleep();//要等一等读锁先获得
} catch (InterruptedException e) {
e.printStackTrace();
}
}

测试一下效果:

public static void main(String[] args) {
  long l1 = System.currentTimeMillis();
  optimisticRead();
  long l2 = writeLock();
  System.out.println(l2-l1);
}

直接看一下输出结果:

数据写入完成的时间比获取读锁晚543ms(说明乐观读并没有阻塞写操作)

5秒后读到的数据仍然是写入前的0

总结

可以看到相比直接用悲观读锁,乐观读锁可以:

1、进入悲观读锁前先看下有没有进入写模式(说白了就是有没有已经获取了悲观写锁)

2、如果其他线程已经获取了悲观写锁,那么就只能老老实实的获取悲观读锁(这种情况相当于退化成了读写锁)

3、如果其他线程没有获取悲观写锁,那么就不用获取悲观读锁了,减少了一次获取悲观读锁的消耗和避免了因为读锁导致写锁阻塞的问题,直接返回读的数据即可(必须再tryOptimisticRead和validate之间获取好数据,否则数据可能会不一致了,试想如果过了validate再获取数据,这时数据可能被修改并且读操作也没有任何保护措施)

StampedLock的理解和使用的更多相关文章

  1. [JDK8]读写锁的改进:StampedLock

    StampedLock是Java8引入的一种新的锁机制,简单的理解,可以认为它是读写锁的一个改进版本,读写锁虽然分离了读和写的功能,使得读与读之间可以完全并发,但是读和写之间依然是冲突的,读锁会完全阻 ...

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

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

  3. Java 8 StampedLock解决同步问题

    Java 8新特性探究(十)StampedLock将是解决同步问题的新宠 JDK8中StampedLock原理探究 深入理解StampedLock及其实现原理 JDK1.8 StampedLock源码 ...

  4. StampedLock

    StampedLock是Java8引入的一种新的所机制,简单的理解,可以认为它是读写锁的一个改进版本,读写锁虽然分离了读和写的功能,使得读与读之间可以完全并发,但是读和写之间依然是冲突的,读锁会完全阻 ...

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

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

  6. Java8 读写锁的改进:StampedLock(笔记)

         StampedLock是Java8引入的一种新的所机制,简单的理解,可以认为它是读写锁的一个改进版本,读写锁虽然分离了读和写的功能,使得读与读之间可以完全并发,但是读和写之间依然是冲突的,读 ...

  7. 【Java并发工具类】StampedLock:比读写锁更快的锁

    前言 ReadWriteLock适用于读多写少的场景,允许多个线程同时读取共享变量.但在读多写少的场景中,还有更快的技术方案.在Java 1.8中, 提供了StampedLock锁,它的性能就比读写锁 ...

  8. 【漫画】读写锁ReadWriteLock还是不够快?再试试StampedLock!

    本文来源于公众号[胖滚猪学编程] 转载请注明出处! 在互斥锁ReentrantLock不好用?试试读写锁ReadWriteLock一文中,我们对比了互斥锁ReentrantLock和读写锁ReadWr ...

  9. 高并发之Phaser、ReadWriteLock、StampedLock

    本系列研究总结高并发下的几种同步锁的使用以及之间的区别,分别是:ReentrantLock.CountDownLatch.CyclicBarrier.Phaser.ReadWriteLock.Stam ...

随机推荐

  1. Linux 设备模型

    在 2.5 开发循环中一个声明的目标是为内核创建一个统一的设备模型. 之前的内核没有单一的数据结 构, 使它们可以来获取关于系统如何整合的信息. 尽管缺乏信息, 有时事情也进行的不错. 新系统, 带 ...

  2. 【Docker】Ubuntu16.04将Docker升级至最新版

    1.使用curl升级到最新版 curl -fsSL https://get.docker.com/ | sh 2.重启Docker sudo systemctl restart docker 3.设置 ...

  3. CString 的成员函数详解

    CSTRING的成员函数详解   typedef ATL::CStringT< TCHAR, StrTraitMFC_DLL< TCHAR > > CString;CStrin ...

  4. WebGPU学习(十一):学习两个优化:“reuse render command buffer”和“dynamic uniform buffer offset”

    大家好,本文介绍了"reuse render command buffer"和"dynamic uniform buffer offset"这两个优化,以及Ch ...

  5. 第四阶段:2.从零打造一款工具APP产品

    1.APP:安卓跟IOS(根据目标用户选择 ,那个先做哪个后做,APP的通过需要审核,其中也有很多技巧). 同时注意设计模版的使用(提高效率).竞品分析也是少不了的.

  6. 洛谷$P2153\ [SDOI2009]$ 晨跑 网络流

    正解:网络流 解题报告: 传送门$QwQ$ 题目好长昂,,,大概概括下$QwQ$.就说有$n$个节点$m$条边,然后要求每次走的路径都不一样,问最多能走多少次,然后在次数最多的前提下问路径最短是多少$ ...

  7. acwing 1250. 格子游戏 并查集

    地址 https://www.acwing.com/problem/content/1252/ Alice和Bob玩了一个古老的游戏:首先画一个 n×nn×n 的点阵(下图 n=3n=3 ). 接着, ...

  8. spring之通过注解方式配置Bean(一)

    (1)组件扫描:spring能够从classpath下自动扫描.侦测和实例化具有特定注解的组件. (2)特定组件包括: @Component:基本注解,标识一个受spring管理的组件: @Respo ...

  9. HDU4352 XHXJ's LIS 题解 数位DP

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4352 题目大意: 求区间 \([L,R]\) 范围内最长上升子序列(Longest increasin ...

  10. Echarts大数据可视化物流航向省份流向迁徙动态图,开发全解+完美参数注释

    最近在研究Echarts的相关案例,毕竟现在大数据比较流行,比较了D3.js.superset等相关的图表插件,还是觉得echarts更简单上手些. 本文是以原生JS为基础,如果使用Vue.js的话, ...