乐趣区

关于java:除了读写锁JUC-下面还有个-StampedLock还不过来了解一下么

前言

在理解完 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 并没有什么关系,它是在本人外部保护了一个双向阻塞队列。

退出移动版