StampedLock支持的三种模式
ReadWriteLock支持两种模式:读锁、写锁;
StampedLock支持三种模式:悲观读锁、写锁、乐观读;
StampedLock的悲观读锁和写锁 与 ReadWriteLock的读锁和写锁 语义相似,允许多个线程获取悲观读锁,只允许一个线程获取写锁,写锁和悲观读锁是互斥的。
不同的是StampedLock的悲观读锁和写锁在加锁成功后,都会返回一个stamp,解锁时,需要传入这个stamp。
final StampedLock sl = new StampedLock();
// 获取、释放悲观读锁示意代码
long stamp = sl.readLock();
try {
//省略业务相关代码
} finally {
sl.unlockRead(stamp);
}
// 获取、释放写锁示意代码
long stamp = sl.writeLock();
try {
//省略业务相关代码
} finally {
sl.unlockWrite(stamp);
}
StampedLock的性能比ReadWriteLock好的关键是支持乐观读的方式。ReadWriteLock支持多个线程同时读,但是当多个线程同时读的时候,所有的写操作会被阻塞;
而StampedLock的乐观读是允许一个线程获取写锁的。
class Point {
private int x, y;
final StampedLock sl = new StampedLock();
//计算到原点的距离
int distanceFromOrigin() {
// 乐观读
long stamp = sl.tryOptimisticRead();
// 读入局部变量,
// 读的过程数据可能被修改
int curX = x, curY = y;
//判断执行读操作期间,
//是否存在写操作,如果存在,则sl.validate返回false
if (!sl.validate(stamp)){
// 升级为悲观读锁
stamp = sl.readLock();
try {
curX = x;
curY = y;
} finally {
//释放悲观读锁
sl.unlockRead(stamp);
}
}
return Math.sqrt(curX * curX + curY * curY);
}
}
StampedLock不可重入,悲观读锁和写锁都不支持条件变量。
使用StampedLock不要调用中断操作,可能引发CPU暴涨,如果需要支持中断功能,一定使用可中断的悲观读锁 readLockInterruptibly() 和写锁 writeLockInterruptibly()。
StampedLock读模板
final StampedLock sl = new StampedLock();
// 乐观读
long stamp = sl.tryOptimisticRead();
// 读入方法局部变量
......
// 校验stamp
if (!sl.validate(stamp)){
// 升级为悲观读锁
stamp = sl.readLock();
try {
// 读入方法局部变量
.....
} finally {
//释放悲观读锁
sl.unlockRead(stamp);
}
}
//使用方法局部变量执行业务操作
......
StampedLock写模板
long stamp = sl.writeLock();
try {
// 写共享变量
......
} finally {
sl.unlockWrite(stamp);
}