多线程(31)StampedLock和ReadWriteLock

StampedLock 是 Java 8 引入的一种新的锁机制,位于 java.util.concurrent.locks 包下。它可以被认为是 ReadWriteLock 的一个改进版,提供了一种乐观的读锁策略,这种策略可以在某些场景下减少锁的竞争,从而提高性能。与 ReadWriteLock 相比,StampedLock 在使用时需要更加注意,因为它的锁方法不支持重入,并且不支持条件变量。

工作原理

StampedLock 提供了三种主要的访问模式:

  1. 写锁(Write Lock)

    • 类似于 ReadWriteLock 的写锁,提供了排他性的访问。
    • 获取写锁时,StampedLock 会阻塞读锁和写锁的获取。
  2. 悲观读锁(Pessimistic Read Lock)

    • 类似于 ReadWriteLock 的读锁,但在 StampedLock 中被称为悲观读锁。
    • 当获取到悲观读锁时,写锁的请求会被阻塞,直到所有悲观读锁都释放。
  3. 乐观读(Optimistic Read)

    • 这是 StampedLock 独有的一种读取模式。
    • 乐观读不会阻塞写锁的获取,也不会获取实际的锁;它会返回一个邮戳(stamp),代表这次读的版本。
    • 在数据实际读取之前,需要检查邮戳,看看在读取过程中有没有写操作进行,如果有,乐观读需要退化为悲观读锁或者重新读取数据。

锁的获取和释放

每次锁的获取操作,无论是读锁还是写锁,StampedLock 都会返回一个表示锁状态的邮戳(stamp)。这个邮戳在锁的释放时必须要提供,作为释放锁的凭证。这是一个与 ReadWriteLock 显著不同的特点,因为 ReadWriteLock 并不需要这样的邮戳。

重要特点

  • 非阻塞的乐观读StampedLock 支持一种非阻塞的读取锁,这可以减少线程阻塞,提高系统吞吐量。

  • 不支持条件变量StampedLock 不支持条件变量。如果需要类似条件变量的特性,需要使用 ReentrantLock 或者 ReadWriteLock

  • 不支持重入StampedLock 的锁不支持重入。如果一个线程已经持有锁,它不能再次获取锁,否则可能会导致死锁。

  • 中断敏感性StampedLock 的锁获取方法提供中断敏感和非中断敏感的版本,这意味着获取锁的操作可以响应中断。

  • 锁的转换StampedLock 允许从读锁转换为写锁,反之亦然,通过使用特定的方法来尝试转换锁,并检查返回的邮戳是否有效。

示例代码

下面展示了一个使用 StampedLock 的简单示例,包括悲观读锁和写锁的使用:

java 复制代码
import java.util.concurrent.locks.StampedLock;

public class StampedLockExample {
    private final StampedLock sl = new StampedLock();

    // 模拟共享资源
    private int sharedState;

    public void write(int newValue) {
        long stamp = sl.writeLock(); // 获取写锁,并返回邮戳
        try {
            sharedState = newValue;
        } finally {
            sl.unlockWrite(stamp); // 释放写锁,并提供邮戳
        }
    }

    public int read() {
        long stamp = sl.readLock(); // 获取悲观读锁,并返回邮戳
        try {
            return sharedState;
        } finally {
            sl.unlockRead(stamp); // 释放读锁,并提供邮戳
        }
    }

    public int optimisticRead() {
        long stamp = sl.tryOptimisticRead(); // 尝试获取乐观读,并返回邮戳
        int currentState = sharedState; // 读取共享资源
        if (!sl.validate(stamp)) { // 检查在读取过程中是否有写操作
            stamp = sl.readLock(); // 退化为悲观读锁
            try {
                currentState = sharedState;
            } finally {
                sl.unlockRead(stamp);
            }
        }
        return currentState;
    }
}

在这个示例中,我们展示了如何在 StampedLock 中获取和释放写锁和悲观读锁,以及如何执行乐观读取并验证它是否仍然有效。注意:在实际使用中,你需要小心地管理锁的释放,以避免死锁和资源泄露。

相关推荐
小王师傅6614 分钟前
【轻松入门SpringBoot】actuator健康检查(中)-group,livenessState,readinessState
java·spring boot·后端
珑墨35 分钟前
【大语言模型】从历史到未来
前端·人工智能·后端·ai·语言模型·自然语言处理·chatgpt
野生技术架构师36 分钟前
SpringBoot健康检查完整指南,避免线上事故
java·spring boot·后端
superman超哥1 小时前
Rust Feature Flags 功能特性:条件编译的精妙艺术
开发语言·后端·rust·条件编译·功能特性·feature flags
2401_837088501 小时前
Spring Boot 常用注解详解:@Slf4j、@RequestMapping、@Autowired/@Resource 对比
java·spring boot·后端
superman超哥1 小时前
Rust Profile-Guided Optimization(PGO):数据驱动的极致性能优化
开发语言·后端·性能优化·rust·数据驱动·pgo
superman超哥1 小时前
Rust 内存对齐与缓存友好设计:性能优化的微观艺术
开发语言·后端·性能优化·rust·内存对齐·缓存优化设计·微观艺术
IT_陈寒1 小时前
SpringBoot 3.2实战:我用这5个冷门特性将接口QPS提升了200%
前端·人工智能·后端
辣机小司1 小时前
【踩坑记录:EasyExcel 生产级实战:策略模式重构与防御性导入导出校验指南(实用工具类分享)】
java·spring boot·后端·重构·excel·策略模式·easyexcel
BingoGo1 小时前
2025 年的 PHP 虽低调内敛没大改 但是更好用了
后端·php