StampedLock java1.8 提供的, 性能比 ReadWriteLock 好.
语法
final StampedLock sl = new StampedLock();
/**
* 悲观读锁
* 与 ReadWriteLock 的读锁相似
* 允许多个线程进行读操作
* 与写锁互斥
**/
// 获取悲观锁
long stamp = sl.readLock();
try {//。。。。}finally {sl.unlockRead(stamp);
}
/**
* 写锁
* 与 ReadWriteLock 的写锁相似
* 只允许一个线程进行写操作
* 与读锁互斥
**/
// 获取写锁
long stamp1 = sl.writeLock();
try{//。。。}finally {
// 释放写锁
sl.unlockWrite(stamp1);
}
/**
* 乐观读锁升级为悲观读
* 锁的严苛程度变强叫做升级,反之叫做降级
**/
// 获取乐观锁
long stamp = sl.tryOptimisticRead();
// 判断执行读操作期间, 是否存在写操作, 如果存在则 sl.validate 返回 false
if (!sl.validate(stamp)){
// 升级为悲观锁
stamp = sl.readLock();
try{//。。。}finally {
// 释放悲观读锁
sl.unlockRead(stamp);
}
StampedLock 提供的乐观读,是允许一个线程获取写锁的,也就是说不是所有的写操作都是被阻塞的。
乐观读和乐观锁是不一样的,乐观读这个操作是无锁的,乐观读认为读的时候不会有写的操作。
示例
import java.util.concurrent.locks.StampedLock;
/**
* 悲观锁乐观锁
**/
public class Point {
private int x;
private int y;
final StampedLock sl = new StampedLock();
// 计算到原点的距离
int distanceFromOrigin() throws Exception{
// 乐观锁
long stamp = sl.tryOptimisticRead();
// 读入局部变量, 读的过程数据可能被修改
int curX = x;
int curY = y;
// 判断执行读操作期间, 是否存在写操作, 如果存在则 sl.validate 返回 false
if (!sl.validate(stamp)){
// 升级为悲观锁
stamp = sl.readLock();
try{
curX = x;
curY = y;
}finally {
// 释放悲观读锁
sl.unlockRead(stamp);
}
}
return (int)Math.sqrt(curX*curX + curY*curY);
}
}
特征
- StampedLock 支持三种模式: 写锁、悲观读和乐观读。
- 允许多 个线程同时获取乐观锁和悲观读锁。
- 只允许一个线程获取写锁,写锁和悲观读锁是互斥的。
- 使用 StampedLock 一定不要调用中断操作,如果需要支持中断功能,一定使用可中断的悲观读锁 readLockInterruptibly() 和写锁 writeLockInterruptibly()。
- StampedLock 里的写锁和悲观读锁加锁成功之后,都会返回一个 stamp;然后解锁的时候,需要传入这个 stamp。
- StampedLock 不支持重入(ReadWriteLock 支持)。
- StampedLock 的悲观读锁、写锁都不支持条件变量。
- StampedLock 支持锁的降级(通过 tryConvertToReadLock() 方法实现)和升级(通过 tryConvertToWriteLock() 方法实现),但是建议你要慎重使用。
数据库中的乐观锁
- 在表中添加一个数值型版本号字段 version。
- 每次更新表时都将 version 字段加 1。
- 修改数据时使用主键和 version 作为修改条件,version 一致则会修改成功。
- 如果修改失败,通过主键查询获取最新数据再执行修改。
码字不易如果对你有帮助请给个关注
爱技术爱生活 QQ 群: 894109590