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

相关推荐
2401_854391086 分钟前
高效开发:SpringBoot网上租赁系统实现细节
java·spring boot·后端
Cikiss14 分钟前
微服务实战——SpringCache 整合 Redis
java·redis·后端·微服务
Cikiss16 分钟前
微服务实战——平台属性
java·数据库·后端·微服务
OEC小胖胖29 分钟前
Spring Boot + MyBatis 项目中常用注解详解(万字长篇解读)
java·spring boot·后端·spring·mybatis·web
2401_857617621 小时前
SpringBoot校园资料平台:开发与部署指南
java·spring boot·后端
计算机学姐1 小时前
基于SpringBoot+Vue的在线投票系统
java·vue.js·spring boot·后端·学习·intellij-idea·mybatis
Yvemil72 小时前
MQ 架构设计原理与消息中间件详解(二)
开发语言·后端·ruby
2401_854391082 小时前
Spring Boot大学生就业招聘系统的开发与部署
java·spring boot·后端
虽千万人 吾往矣3 小时前
golang gorm
开发语言·数据库·后端·tcp/ip·golang
这孩子叫逆3 小时前
Spring Boot项目的创建与使用
java·spring boot·后端