除了读写锁,JUC 下面还有个 StampedLock!还不过来了解一下么?

前言


在了解完 ReentrantLock 和 ReentrantReadWriteLock 之后,惊奇的发现 JUC 下还有一个 StampedLock 。 查阅资料发现是 JDK8 新增的一个锁。现在已经 JDK15 了,原谅我的孤陋寡闻,实在是业务开发中用的太少。那行吧,赶紧来看一下 StampedLock 到底是什么?为什么有了 ReentrantLock 和 ReentrantReadWriteLock 之后还要设计一个 StampedLock ?


公众号:liuzhihangs,记录工作学习中的技术、开发及源码笔记;时不时分享一些生活中的见闻感悟。欢迎大佬来指导!

介绍

往期回顾

在介绍 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

StampedLock-uml-Wq0Jz2

通过 UML 可以看出 StampedLock 和 AQS 并无任何关系。

StampedLock 和 ReentrantReadWriteLock 的区别?
  1. StampedLock 也是读写锁,但是和 AQS 没有关系
  2. StampedLock 除了 读锁和写锁,还有一个乐观读。
  3. StampedLock 的读锁可以升级为写锁。
  4. StampedLock 不支持锁重入。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

程序员小航

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值