StampedLock
是 Java 8 引入的一种锁机制,位于 java.util.concurrent.locks
包中。
它提供了一种比传统的读写锁(如 ReentrantReadWriteLock
)更灵活和高效的替代方案,特别适用于读操作远多于写操作的场景。
StampedLock
的主要特点是它返回一个类似于“邮戳”(stamp)的值来表示获取锁的状态,并且提供了三种模式:写锁、读锁和乐观读锁。
主要特点
- 写锁:独占锁,当一个线程持有写锁时,其他任何线程都不能获得读锁或写锁。
- 读锁:共享锁,允许多个线程同时持有读锁,但前提是没有任何线程持有写锁。
- 乐观读锁:一种非阻塞的读锁方式,假设在读取期间没有发生写操作。如果在读取过程中发生了写操作,则需要重试读取过程。
基本使用方法
获取写锁
StampedLock lock = new StampedLock();
long stamp = lock.writeLock(); // 获取写锁
try {
// 执行写操作
} finally {
lock.unlockWrite(stamp); // 释放写锁
}
获取读锁
long stamp = lock.readLock(); // 获取读锁
try {
// 执行读操作
} finally {
lock.unlockRead(stamp); // 释放读锁
}
使用乐观读锁
乐观读锁不实际阻止其他线程获取写锁,而是通过验证“邮戳”来检查是否有写操作发生过。
long stamp = lock.tryOptimisticRead(); // 尝试获取乐观读锁
// 执行读操作
if (!lock.validate(stamp)) { // 验证是否在读期间有写操作发生
stamp = lock.readLock(); // 如果有写操作发生,升级为真实读锁
try {
// 重新执行读操作
} finally {
lock.unlockRead(stamp);
}
}
适用场景
- 当系统中读操作远远多于写操作时,
StampedLock
可以提供比传统读写锁更好的性能,因为它允许读操作在没有写操作的情况下无需等待。 - 在某些情况下,使用乐观读锁可以进一步提高性能,因为它们避免了实际获取锁带来的开销,但需要确保在读取的数据一致性不是严格要求的情况下使用。
注意事项
StampedLock
不支持重入(即一个线程不能多次获取同一个锁),这与ReentrantReadWriteLock
不同。- 乐观读锁的使用需谨慎,因为它可能需要重试逻辑,增加了代码复杂度。
StampedLock
没有实现Condition
接口,这意味着它不支持像条件变量那样的等待/通知机制。
总之,StampedLock
提供了一种高效处理读多写少场景的方式,特别是其乐观读模式能够在保证一定并发度的同时减少锁竞争带来的开销。然而,在选择使用 StampedLock
之前,开发者需要仔细评估应用场景的具体需求,包括对数据一致性的要求以及潜在的重试逻辑复杂性。
THE END