前言


在理解完 ReentrantLock 和 ReentrantReadWriteLock 之后,惊奇的发现 JUC 下还有一个 StampedLock 。 查阅材料发现是 JDK8 新增的一个锁。当初曾经 JDK15 了,原谅我的见多识广,切实是业务开发中用的太少。那行吧,连忙来看一下 StampedLock 到底是什么?为什么有了 ReentrantLock 和 ReentrantReadWriteLock 之后还要设计一个 StampedLock ?


公众号:『 刘志航 』,记录工作学习中的技术、开发及源码笔记;时不时分享一些生存中的见闻感悟。欢送大佬来领导!

介绍

往期回顾

在介绍 StampedLock 之前还是先看一下 ReentrantLock 和 ReentrantReadWriteLock。

ReentrantLock:互斥锁,同时只有一个线程能够持有。反对锁重入。

ReentrantReadWriteLock:读写锁,分为读锁和写锁,反对重入。其中读读共享,写写独占,读写互斥,写读互斥。反对锁降级,线程获取写锁后能够降级为读锁。适宜读多写少的场景。

那为什么要设计 StampedLock 呢?先来看一下源码上的正文:

StampedLock

基于性能的锁,具备三种模式来管制读/写访问。StampedLock的状态由版本和模式组成。锁获取办法返回一个 stamp 用来示意并管制锁状态的拜访;这些办法的“try”版本可能会返回非凡值零,以示意无奈获取拜访权限。
锁的开释和转换方法须要应用 stamp 作为参数,如果它们与锁的状态不匹配,则会失败。

三种模式是:写锁、读锁、乐观读锁。

并且具备以下特色:

  1. 获取锁的时候(无论读锁还是写锁或者乐观读锁)都会返回一个 stamp,在开释锁的时候须要应用这个 stamp;
  2. 反对三种模式转换;
  3. 不是可重入的,所以取得锁的时候,不要尝试再次获取。

应用样例

/** * @author liuzhihang * @date 2020/8/6 15:27 */public class Count {    private int num;    private final StampedLock stampedLock = new StampedLock();    // 应用写锁,在对 num 进行写入的时候加锁    void write(int x) {        long stamp = stampedLock.writeLock();        try {            num += x;        } finally {            stampedLock.unlockWrite(stamp);        }    }    // 乐观读    int read() {        // 获取乐观读锁;返回 stamp        long stamp = stampedLock.tryOptimisticRead();        try {            // validate 验证是否被写锁持有            // 没有被写锁持有,能够间接返回            if (!stampedLock.validate(stamp)) {                // 被写锁持有,那只能获取读锁                stamp = stampedLock.readLock();            }            return num;        } finally {            stampedLock.unlockRead(stamp);        }    }    void convertWrite(int x) {        // 读        long stamp = stampedLock.readLock();        try {            while (num == x) {                // 满足条件,转换为写锁                long ws = stampedLock.tryConvertToWriteLock(stamp);                // 转为写锁胜利                if (ws != 0L) {                    stamp = ws;                    num = x;                    break;                } else {                    // 转换失败,开释读锁                    stampedLock.unlockRead(stamp);                    // 再次获取写锁                    stamp = stampedLock.writeLock();                }            }        } finally {            stampedLock.unlock(stamp);        }    }}
  1. 写锁应用办法一样;
  2. 乐观读,能够先去读数据,发现没有扭转能够返回,发现扭转了,则从新获取读锁,而后再返回;
  3. 读锁能够降级为写锁,通过 tryConvertToWriteLock 办法。

总结

UML

通过 UML 能够看出 StampedLock 和 AQS 并无任何关系。

StampedLock 和 ReentrantReadWriteLock 的区别?

  1. StampedLock 也是读写锁,然而和 AQS 没有关系
  2. StampedLock 除了 读锁和写锁,还有一个乐观读。
  3. StampedLock 的读锁能够降级为写锁。
  4. StampedLock 不反对锁重入。

小结

本文次要介绍 StampedLock 的相干应用及和 ReentrantReadWriteLock 的区别。

因为工作的确很少应用,浏览源码,外部自旋逻辑等有很多。如果介绍的话会篇幅特地长,这里就省略了。有趣味的小伙伴能够本人浏览源码。

因为 StampedLock 提供的乐观读锁反对,所以在多线程多读状况下,性能比 ReentrantReadWriteLock 要更好,然而须要留神的是 StampedLock 是不反对锁重入的。

另一个须要记住的就是 StampedLock 和 AQS 并没有什么关系,它是在本人外部保护了一个双向阻塞队列。