在JDK8中,又引入了一款新式武器StampedLock。这是一个什么东西呢?英文单词Stamp,意思是邮戳。那在这里有用什么含义呢?傻瓜,请看下面的分解。 聪明的你一定也猜到了,StampedLock就是提供了一种乐观锁的工具,因此,它是对重入锁的一个重要的补充。
插播一些内容,我有个同事为了解决写饥饿的问题使用了StampedLock,而并没有用tryOptimisticRead(),单纯以为StampedLock解决了写饥饿的问题,但实际上不用tryOptimisticRead 所以我觉得在说StampedLock的具体实现之前,有必要先来看下StampedLock的正确使用方式。 public class StampedLockDemo { private StampedLock stampedLock = new StampedLock(); private int stampedLock.validate(stamp)) { // 2 try { stamp = stampedLock.readLock( Pessimistic locking 深入理解StampedLock及其实现原理 StampedLock源码分析 死磕 java同步系列之StampedLock源码解析
2.邮戳锁StampedLock 无锁→独占锁→读写锁→邮戳锁 1.简介 StampedLock是JDK1.8中新增的一个读写锁,也是对JDK1.5中的读写锁ReentrantReadWriteLock ; public class StampedLockDemo { static int number = 37; static StampedLock stampedLock = new StampedLock(); public void write() { long stamp = stampedLock.writeLock(); System.out.println("4秒前stampedLock.validate值(true无修改,false有修改)"+"\t"+stampedLock.validate(stamp)); 的缺点 1)StampedLock 不支持重入,没有Re开头 2)StampedLock 的悲观读锁和写锁都不支持条件变量(Condition),这个也需要注意。
ReadWriteLock支持两种模式一种读锁,一种写锁,而StampedLock支持三个模式,写锁,悲观读锁,乐观读锁,其中写锁和悲观读锁和读写锁的写锁,读锁语义基本一致,允许多个线程同时获取悲观读锁 ,但是只有一个线程获取写锁,且写锁和读锁互斥,不同的是StampedLock里面的写锁和悲观读锁加锁成功之后,会返回一个stamp,当解锁的时候需要传入这个stamp final StampedLock sl = new StampedLock(); // 获取/释放悲观读锁示意代码 long stamp = sl.readLock(); try { //省略业务相关代码 } finally { 我们可以看一下官方给出的代码,如下 class Point { private int x, y; final StampedLock sl = new StampedLock(); //计算到原点的距离 我们使用StampedLock虽然性能很好,但是他并不支持重入,且StampedLock的悲观读锁,写锁都不支持条件变量,最后一点最为重要,如果线程阻塞在StampedLock的readLock或者writeLock
> k = StampedLock.class; Class<? 但是我们发现StampedLock并没有使用AQS来进行多线程的调度,然后自己实现了一套。这可能和java8的新增有关系。 ? 根据上边的描述,我们看一下StampedLock的加锁过程。 通过查看StampedLock的源码,发现基本都是通过Unsafe去操作内存的。也没有AQS那么复杂,但是对内存的操作和相关逻辑在StampedLock确实比较复杂。 总结 StampedLock提供了乐观读锁,能够替代ReadWriteLock提升并发性能。 StampedLock是不可重入锁。
特性与 ReadWriteLock 类似,StampedLock 也支持多个线程同时获取读锁,但只允许一个线程获取写锁。 使用场景StampedLock 适用于读远远大于写的场景,并且对数据的一致性要求不高,例如统计数据、监控系统等。 示例代码下面是一个使用 StampedLock 的示例,实现了一个计数器:import java.util.concurrent.locks.StampedLock;public class Counter { private int count = 0; private StampedLock lock = new StampedLock(); public int getCount( 总结ReadWriteLock 和 StampedLock 都是Java中用于并发控制的重要机制。
StampedLock是Java 8引入的一种乐观读锁和悲观写锁的实现,它提供了一种更高效的读写锁机制。 下面是对StampedLock的实现原理、结构和核心方法的详细解释: 实现原理 StampedLock的实现基于乐观读锁和悲观写锁的机制,它使用一个名为stamp的整数来表示锁的状态。 StampedLock内部使用CAS操作来更新锁的状态。 结构 StampedLock的内部结构比较简单,主要包括两个核心组件:一个是一个名为Synchronizer的内部类,用于管理锁的状态和线程的等待队列;另一个是一个名为WNode的内部类,用于表示等待节点 需要注意的是,StampedLock相对于ReentrantLock来说,更适合读多写少的场景,并且在使用时需要谨慎处理乐观读锁的有效性验证。
要进一步提升并发执行效率,Java 8 引入了新的读写锁:StampedLock。 StampedLock 和 ReadWriteLock 相比,改进之处在于:读的过程中也允许获取写锁后写入! public class T { private final StampedLock stampedLock = new StampedLock(); private double stampedLock.validate(stamp)) { // 检查乐观读锁后是否有其他写锁发生 stamp = stampedLock.readLock(); // 获取一个悲观读锁 可见,StampedLock 把读锁细分为乐观读和悲观读,能进一步提升并发效率。但这也是有代价的:一是代码更加复杂,二是 StampedLock 是不可重入锁,不能在一个线程中反复获取同一个锁。 小结 StampedLock 提供了乐观读锁,可取代 ReadWriteLock 以进一步提升并发性能; StampedLock 是不可重入锁。
StampedLock的状态由一个版本和模式来组成. 锁的申请方法返回一个stamp,释放锁的时候需要这个参数,如果传入的stamp和锁的状态不匹配,则释放失败. StampedLock是可序列化的,但是会反序列化成最初的未加锁状态,因此不能用来做远程加锁. 像Semaphore,但是和大多数锁的实现不一样,StampedLock没有持有者的概念,一个线程申请的锁可能会被其他线程释放掉. 然而,一个StampedLock可以当做一个读锁,写锁,或者读写锁. 简单的使用案例: 一个类维护简单的二维点. class Point { private double x, y; private final StampedLock sl = new StampedLock(); //
1、什么是StampedLock? StampedLock,也即邮戳锁,是jdk8中推出的对读写锁的缺点进行改进的邮戳锁,它推出了乐观读写来改进大量并发读,少量写的情况的性能。 StampedLock是不可重入的,使用时需特别注意。 2、StampedLock三种模式 StampedLock有三种模式,读写 可以 相互转换: Writing:写模式 Reading:悲观读模式 Optimistic Reading:乐观读模式 一个 stampedLock = new StampedLock(); public void put(Integer key , String value) { // 上写锁 stampedLock.validate(stamp)) { // 上悲观锁 stamp = stampedLock.readLock();
要进一步提升并发执行效率,Java 8引入了新的读写锁:StampedLock。 StampedLock和ReadWriteLock相比,改进之处在于:读的过程中也允许获取写锁后写入! 我们来看例子: public class Point { private final StampedLock stampedLock = new StampedLock(); private stampedLock.validate(stamp)) { // 检查乐观读锁后是否有其他写锁发生 stamp = stampedLock.readLock(); // 获取一个悲观读锁 可见,StampedLock把读锁细分为乐观读和悲观读,能进一步提升并发效率。但这也是有代价的: 一是代码更加复杂 二是StampedLock是不可重入锁,不能在一个线程中反复获取同一个锁。 StampedLock小结 StampedLock提供了乐观读锁,可取代ReadWriteLock以进一步提升并发性能; StampedLock是不可重入锁。
接下来几篇文章会对JUC并发包里面的锁工具类做下梳理,如:ReentrantLock、 ReentrantReadWriteLock、StampedLock 三种模式: 写锁 悲观读锁 乐观读 其中 不同的是:StampedLock 里的写锁和悲观读锁加锁成功之后,都会返回一个 stamp;然后解锁的时候,需要传入这个 stamp。 ReadWriteLock比较: ReadWriteLock 支持多个线程同时读,但是当多个线程同时读的时候,所有的写操作会被阻塞,可能导致写的饥饿问题(读操作一直都能抢占到CPU时间片,而写操作一直抢不了) StampedLock 主要是 StampedLock 支持乐观读的方式。当在乐观读期间,允许另一个线程获取写锁。那么怎样保证读和写的一致性呢?通过validate()方法,如果校验不通过,说明期间有修改,可以再重试一次。 乐观读,使用模板: final StampedLock sl = new StampedLock(); // 乐观读 long stamp = sl.tryOptimisticRead(); /
但是很容易造成 “饥饿问题”: 读线程非常多,写线程很少的情况下,很容易导致写线程 “饥饿” StampedLock 支持的三种锁模式 我们先来看看在使用上StampedLock 和上一篇文章讲的 ReadWriteLock StampedLock 支持三种模式,分别是:写锁、悲观读锁和乐观读。 这个 version 字段就类似于 StampedLock 里面的 stamp。这样对比着看,相信你会更容易理解 StampedLock 里乐观读的用法。 StampedLock 代码示例 class Point { // 共享变量 x、y 坐标 private double x, y; private final StampedLock StampedLock 在命名上并没有增加 Reentrant,想必你已经猜测到 StampedLock 应该是不可重入的。事实上,的确是这样的,StampedLock 不支持重入。
1.特点展示相比于 Java 中的其他锁,StampedLock 具有以下特点:读写分离:StampedLock 支持读写分离,读锁和写锁可以同时被不同的线程持有,从而提高了并发性能。 性能优势:StampedLock 在多线程并发中的读多情况下有更好的性能,因为 StampedLock 获取乐观读锁时,不需要通过 CAS 操作来设置锁的状态,只是简单地通过测试状态即可。 的执行效率就会更高,它是使用如下:// 创建 StampedLock 实例StampedLock lock = new StampedLock();// 获取乐观读锁long stamp = lock.tryOptimisticRead 3.注意事项在使用 StampedLock 时,需要注意以下几个问题:不可重入性:StampedLock 的读锁和写锁都不支持重入,这意味着一个线程在获取了锁之后,不能再次获取同一个锁,所以在使用 StampedLock 课后思考如何避免 StampedLock CPU 100% 的问题?
文章目录 概述 三种读写模式的锁 写锁writeLock 悲观读锁readLock 乐观读锁tryOptimisticRead 概述 StampedLock是并发包里面JDK8版本新增的一个锁,该锁提供了三种模式的读写控制 三种读写模式的锁 StampedLock提供的三种读写模式的锁分别如下 写锁writeLock 悲观读锁readLock 乐观读锁tryOptimisticRead 写锁writeLock 写锁writeLock :是一个排它锁或者独占锁,某时只有一个线程可以获取该锁,当一个线程获取该锁后,其他请求读锁和写锁的线程必须等待,这类似于ReentrantReadWriteLock的写锁(不同的是StampedLock
今天我们来聊一个JDK1.8中引入了的并发锁StampedLock,它跟其他的锁有什么优势呢? 初识StampedLock 让我们来看一下官方的示例: class Point { private double x, y; private final StampedLock sl = new public static void main(String[] args) { StampedLock sl = new StampedLock(); LocalThreadPool.run StampedLock是非公平锁,因为每次获取都会尝试自旋直接获取。 StampedLock的数据结构比较特别,整个等待队列是FIFO队列,但是读锁队列是LIFO队列。
上一篇介绍了StampedLock存在的意义以及如何使用StampedLock,按照这个系列的风格大家也应该猜到了,这一篇就是StampedLock的源码分析。 锁状态 StampedLock属性 写锁获取与释放 悲观读锁读取与释放 乐观读锁读取 1. 锁状态 StampedLock提供了写锁、悲观读锁、乐观读锁三种模式的锁,如何维护锁状态呢? StampedLock的锁状态用 long 类型的 state 表示,类似ReentrantReadWriteLock,通过将 state 按位切分的方式表示不同的锁状态。 StampedLock同样采用这种方法,将获取写锁的次数作为版本号,也就是乐观读锁的票据,写锁释放时次数加 1,也就是 state 第 8 位加 1。 结点 StampedLock中,等待队列的结点要比 AQS 中简单些,仅仅三种状态。0:初始状态;-1:等待中;1:取消。结点的定义中有个 cowait 字段,该字段指向一个栈,用于保存读线程。
4.8 JDK8新增的StampedLock锁探究 StampedLock是并发包里面jdk8版本新增的一个锁,该锁提供了三种模式的读写控制,三种模式分别如下: 写锁writeLock,是个排它锁或者叫独占锁 class Point { // 成员变量 private double x, y; // 锁实例 private final StampedLock sl = new StampedLock(); // 排它锁-写锁(writeLock) void move(double deltaX, double deltaY) { long // 释放锁(6) sl.unlock(stamp); } } } 如上代码Point类里面有两个成员变量,和三个操作成员变量的方法,另外实例化了一个StampedLock lock.unlock(stamp);//释放悲观锁 } } useThreadMemoryVarables();//使用线程本地堆栈里面的数据进行操作 总结: 相比ReentrantLock读写锁,StampedLock
---- 问题 (1)StampedLock是什么? (2)StampedLock具有什么特性? (3)StampedLock是否支持可重入? (4)StampedLock与ReentrantReadWriteLock的对比? StampedLock具有三种模式:写模式、读模式、乐观读模式。 使用方法 让我们通过下面的例子了解一下StampedLock三种模式的使用方法: class Point { private double x, y; private final StampedLock 总结 StampedLock的源码解析到这里就差不多了,让我们来总结一下: (1)StampedLock也是一种读写锁,它不是基于AQS实现的; (2)StampedLock相较于ReentrantReadWriteLock
StampedLock的调度策略并不能始终如一地偏向读而不是写,反之亦然。所有“try”方法都是尽力而为,不一定符合任何调度或公平性策略。 class Point { private double x, y; private final StampedLock sl = new StampedLock(); void StampedLock根据这个类中的成员变量state的状态,来决定其是否能被获得读锁或者是写锁。 6.总结 本文对StampedLock的源码及注释部分进行了分析,可以知道,StampedLock实际上没有采用AQS来实现,而是采用了与AQS类似的一种比较简单的CLH队列来实现。 但是需要注意的是,StampedLock虽然有很多有点,但是并不支持重入。后续将对stampedLock和ReentrentReadWriteLock对比分析,及其应用场景。