StampedLock 是 Java 8 引入的一种新的锁机制,旨在提供更高的并发性能,特别是在读多写少的场景中。它是 ReentrantReadWriteLock 的增强版,通过引入“戳记(Stamp)”概念,提供了更灵活的锁控制方式。

核心特点

三种模式

  • 写锁(Write Lock)

    • 独占锁,类似于 ReentrantReadWriteLock 的写锁;

    • 同一时刻只有一个线程可以获取写锁。

  • 读锁(Read Lock)

    • 共享锁,类似于 ReentrantReadWriteLock 的读锁;

    • 多个线程可以同时获取读锁。

  • 乐观读(Optimistic Read)

    • 一种无锁的读模式,允许在不阻塞写锁的情况下进行读操作;

    • 在读操作完成后,需要验证戳记(Stamp)以确保数据的一致性。

戳记(Stamp)

  • 每次获取锁时都会返回一个戳记(long 类型的值);

  • 戳记用于后续的锁释放或验证操作。

主要方法

写锁

  • long writeLock():获取写锁,返回戳记;

  • void unlockWrite(long stamp):释放写锁,需要传入对应的戳记。

读锁

  • long readLock():获取读锁,返回戳记;

  • void unlockRead(long stamp):释放读锁,需要传入对应的戳记。

乐观读

  • long tryOptimisticRead():尝试获取乐观读锁,返回戳记;

  • boolean validate(long stamp):验证戳记是否有效(即在此期间是否有写操作发生)。

锁转换

  • long tryConvertToWriteLock(long stamp):尝试将读锁转换为写锁;

  • long tryConvertToReadLock(long stamp):尝试将写锁转换为读锁。

优点

  • 高性能:乐观读模式避免了读操作与写操作的冲突,显著提高了读多写少场景的性能;

  • 灵活性:支持锁的升级(读锁转写锁)和降级(写锁转读锁)。

缺点

  • 复杂性:使用 StampedLock 需要更复杂的代码逻辑,尤其是乐观读模式;

  • 不支持条件变量:StampedLock 不支持类似 Condition 的条件变量,因此不能用于需要等待通知的场景;

  • 无重入性:StampedLock 不是可重入锁,因此需要避免死锁。

示例代码

import java.util.concurrent.locks.StampedLock;

public class StampedLockExample {
    private final StampedLock stampedLock = new StampedLock();
    private int value = 0;

    // 写操作
    public void write(int newValue) {
        long stamp = stampedLock.writeLock(); // 获取写锁
        try {
            value = newValue;
        } finally {
            stampedLock.unlockWrite(stamp); // 释放写锁
        }
    }

    // 读操作(悲观读)
    public int read() {
        long stamp = stampedLock.readLock(); // 获取读锁
        try {
            return value;
        } finally {
            stampedLock.unlockRead(stamp); // 释放读锁
        }
    }

    // 读操作(乐观读)
    public int optimisticRead() {
        long stamp = stampedLock.tryOptimisticRead(); // 尝试乐观读
        int currentValue = value;
        if (!stampedLock.validate(stamp)) { // 验证戳记
            stamp = stampedLock.readLock(); // 获取读锁
            try {
                currentValue = value;
            } finally {
                stampedLock.unlockRead(stamp); // 释放读锁
            }
        }
        return currentValue;
    }

    public static void main(String[] args) {
        StampedLockExample example = new StampedLockExample();

        // 写线程
        new Thread(() -> {
            for (int i = 0; i < 10; i++) {
                example.write(i);
                System.out.println("Write: " + i);
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                }
            }
        }).start();

        // 读线程
        new Thread(() -> {
            for (int i = 0; i < 10; i++) {
                int result = example.optimisticRead();
                System.out.println("Read: " + result);
                try {
                    Thread.sleep(50);
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                }
            }
        }).start();
    }
}