首先了解悲观锁和乐观锁概念
悲观锁:假设会发生并发冲突,屏蔽一切可能违反数据完整性的操作
读取悲观锁:在读取之前先判断以下,数据有无修改。
乐观锁:假设不会发生并发冲突,只在提交操作前检查是否违反数据完整性的操作
读取乐观锁:在读取之前不需要判断数据是否被修改,只需读取自己的数据
StampedLock
StampedLock是基于能力的锁,很好的实现悲观锁和乐观锁的逻辑。
使用三种模式控制读-写访问
StampedLock的状态包含版本和模式,获取锁方法根据锁状态返回一个表示控制表示的标识(stamp)
“try”版本的方法返回特殊值”0”表示获取失败
锁释放需要一个标识作为参数。如果不符合锁状态则失败
3种模式
写
writeLock可能阻塞等待独占访问,返回一个标志,用在unlockWrite释放锁。也提供无时间或者带时间版本的tryWriteLock方法
当锁以写模式持有时,没有读锁可获取。所有乐观性读确认失败读
readLock阻塞等待非独占访问,用在unlockRead释放锁。也提供无时间或者带时间版本的tryWriteLock方法
乐观读
只有在锁没有以写模式持有时,tryOptimisticRcad()返回一个非0标识。
如果锁自给定标识没有写模式持有,validate()返回true(可认为极弱版本的读锁,可在任意时间被写入打破)
在短的只读代码使用乐观模式可以减少竞争,提高吞吐。StampedLock
利用Lock机制+Stamp标记状态。实现锁与锁之间乐观和悲观
Java Doc Example
public class StampedLockDemo {
private double x;
private double y;
final StampedLock lock = new StampedLock();
//一个简单的写模式例子
public void move(double deltaX, double deltaY){
//标志
long stamp = lock.writeLock();
try {
x += deltaX;
y += deltaY;
} finally{
lock.unlockWrite(stamp);
}
System.out.println("写入...x = " + x + " " + "y = " + y);
}
//乐观读锁
public double distanceFromOrigin(){
long stamp = lock.tryOptimisticRead();
double currentX = x;
double currentY = y;
System.out.println("读取...x = " + x + " " + "y = " + y);
//检查是否有写锁发生
if(!lock.validate(stamp)){
stamp = lock.readLock();
try {
currentX = x;
currentY = y;
} finally{
lock.unlockRead(stamp);
}
}
return Math.sqrt(currentX * currentX + currentY * currentY);
}
//悲观锁
public void moveIfAtOrigin(double newX, double newY){
long readStamp = lock.readLock();
try{
//检查状态是否符合
while(x == 10.0 && y == 10.0){
//将读锁转为写锁
long writeStamp = lock.tryConvertToWriteLock(readStamp);
//确认写锁是否成功
if(writeStamp != 0L){
readStamp = writeStamp;//成功则替换
x = newX;
y = newY;
break;
}else{
lock.unlockRead(readStamp);
readStamp = lock.writeLock();
}
}
System.out.println("读锁变为写锁后:x = "+x + " y = " + y);
}finally{
lock.unlock(readStamp);
}
}
}
运行
public static void main(String[] args) {
StampedLockDemo demo = new StampedLockDemo();
demo.move(10,10);
System.out.println(demo.distanceFromOrigin());
demo.moveIfAtOrigin(100,200);
}
console
写入...x = 10.0 y = 10.0
读取...x = 10.0 y = 10.0
14.142135623730951
读锁变为写锁后:x = 100.0 y = 200.0