多线程(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 中获取和释放写锁和悲观读锁,以及如何执行乐观读取并验证它是否仍然有效。注意:在实际使用中,你需要小心地管理锁的释放,以避免死锁和资源泄露。

相关推荐
zopple4 小时前
常见的 Spring 项目目录结构
java·后端·spring
cjy0001116 小时前
springboot的 nacos 配置获取不到导致启动失败及日志不输出问题
java·spring boot·后端
小江的记录本7 小时前
【事务】Spring Framework核心——事务管理:ACID特性、隔离级别、传播行为、@Transactional底层原理、失效场景
java·数据库·分布式·后端·sql·spring·面试
sheji34167 小时前
【开题答辩全过程】以 基于springboot的校园失物招领系统为例,包含答辩的问题和答案
java·spring boot·后端
程序员cxuan7 小时前
人麻了,谁把我 ssh 干没了
人工智能·后端·程序员
wuyikeer8 小时前
Spring Framework 中文官方文档
java·后端·spring
Victor3569 小时前
MongoDB(61)如何避免大文档带来的性能问题?
后端
Victor3569 小时前
MongoDB(62)如何避免锁定问题?
后端
wuyikeer9 小时前
Spring BOOT 启动参数
java·spring boot·后端
子木HAPPY阳VIP10 小时前
Ubuntu 22.04 VMware 设置固定IP配置
人工智能·后端·目标检测·机器学习·目标跟踪