StampedLock 是 Java 8 引入的一种新的锁机制,位于 java.util.concurrent.locks
包中。它提供了三种模式的锁控制:写锁、悲观读锁和乐观读锁。StampedLock 的设计旨在提供更高的并发性能,尤其是在读多写少的场景中。
1. 写锁(Write Lock)
- 写锁是独占锁,类似于
ReentrantReadWriteLock
的写锁。 - 当一个线程获取了写锁后,其他线程无法获取读锁或写锁,直到写锁被释放。
- 写锁的获取会返回一个 stamp(戳记),用于后续的解锁操作。
StampedLock stampedLock = new StampedLock();
long stamp = stampedLock.writeLock();
try {
// 写操作
} finally {
stampedLock.unlockWrite(stamp);
}
2. 悲观读锁(Pessimistic Read Lock)
- 悲观读锁是共享锁,类似于
ReentrantReadWriteLock
的读锁。 - 多个线程可以同时获取悲观读锁,但在有线程持有写锁时,读锁会被阻塞。
- 悲观读锁的获取也会返回一个 stamp。
long stamp = stampedLock.readLock();
try {
// 读操作
} finally {
stampedLock.unlockRead(stamp);
}
3. 乐观读锁(Optimistic Read Lock)
- 乐观读锁是一种无锁的读操作,它不会阻塞其他线程的写操作。
- 乐观读锁的获取会返回一个 stamp,但在实际读取数据之前,需要调用
validate(stamp)
方法来检查在此期间是否有写操作发生。 - 如果
validate(stamp)
返回true
,说明没有写操作发生,读取的数据是有效的;否则,需要升级为悲观读锁或写锁。
long stamp = stampedLock.tryOptimisticRead();
// 读操作
if (!stampedLock.validate(stamp)) {
// 如果验证失败,升级为悲观读锁
stamp = stampedLock.readLock();
try {
// 重新读操作
} finally {
stampedLock.unlockRead(stamp);
}
}
4. 锁的转换
- StampedLock 支持锁的转换,例如从读锁转换为写锁,或者从写锁转换为读锁。
- 锁的转换通常需要先释放当前锁,再获取新的锁。
long stamp = stampedLock.readLock();
try {
// 读操作
// 转换为写锁
long writeStamp = stampedLock.tryConvertToWriteLock(stamp);
if (writeStamp != 0L) {
stamp = writeStamp;
// 写操作
} else {
stampedLock.unlockRead(stamp);
stamp = stampedLock.writeLock();
// 写操作
}
} finally {
stampedLock.unlock(stamp);
}
5. 性能优势
- StampedLock 的性能通常优于
ReentrantReadWriteLock
,尤其是在读多写少的场景中。 - 乐观读锁的使用可以进一步提高并发性能,因为它避免了不必要的锁竞争。
6. 注意事项
- StampedLock 不支持重入,即同一个线程不能多次获取同一个锁。
- StampedLock 不支持条件变量(Condition),如果需要条件变量,可以考虑使用
ReentrantLock
。
总结
StampedLock 是 Java 中一种高效的锁机制,适用于读多写少的并发场景。它通过提供写锁、悲观读锁和乐观读锁三种模式,以及锁的转换功能,能够显著提高并发性能。然而,使用 StampedLock 时需要注意其不支持重入和条件变量的特性。
THE END
暂无评论内容