StampedLock是Java 8引入的一种新的读写锁,它有以下特点:
- StampedLock不支持重入,也就是说同一个线程不能多次获取同一个锁。
- StampedLock提供了三种模式的锁:写锁、悲观读锁和乐观读锁。
- 写锁是独占的,只有在没有其他线程持有读锁或写锁的情况下才能获取。
- 悲观读锁是共享的,可以允许多个线程同时读取,但是在获取悲观读锁的过程中会阻止写锁的获取。
- 乐观读锁是一种非阻塞的读锁,它假设在读取的过程中不会有其他线程进行写操作,因此不会加锁,只会返回一个版本号(stamp)。这个版本号可以用来在读取结束后验证是否有写操作发生。如果没有发生写操作,那么读取就是有效的。如果发生了写操作,那么乐观读锁就可能失效,需要重新获取。
- StampedLock提供了一些方法来实现锁的转换。例如,tryConvertToWriteLock方法可以把一个读锁转换为写锁,前提是没有其他线程持有读锁。这样可以减少锁的获取和释放的开销。
下面是一些使用StampedLock的业务代码示例:
// 创建一个StampedLock对象:
StampedLock lock = new StampedLock();
// 获取写锁,并返回一个stamp:
long stamp = lock.writeLock();
try {
// 写入数据:
writeData();
} finally {
// 释放写锁:
lock.unlockWrite(stamp);
}
// 获取悲观读锁,并返回一个stamp:
stamp = lock.readLock();
try {
// 读取数据:
readData();
} finally {
// 释放悲观读锁:
lock.unlockRead(stamp);
}
// 尝试获取乐观读锁,并返回一个stamp:
stamp = lock.tryOptimisticRead();
// 读取数据:
readData();
// 验证stamp是否有效:
if (!lock.validate(stamp)) {
// 如果无效,说明有写操作发生,需要重新获取悲观读锁:
stamp = lock.readLock();
try {
// 重新读取数据:
readData();
} finally {
// 释放悲观读锁:
lock.unlockRead(stamp);
}
}
// 尝试把悲观读锁升级为写锁,并返回一个新的stamp:
long newStamp = lock.tryConvertToWriteLock(stamp);
if (newStamp == 0L) {
// 如果失败,说明有其他线程持有读锁或写锁,需要先释放悲观读锁,再获取写锁:
lock.unlockRead(stamp);
newStamp = lock.writeLock();
}
try {
// 写入数据:
writeData();
} finally {
// 释放写锁:
lock.unlockWrite(newStamp);
}