StampedLock知识点梳理

2020-08-19 17:01:39 浏览数 (2)

接下来几篇文章会对JUC并发包里面的锁工具类做下梳理,如:ReentrantLock、

ReentrantReadWriteLock、StampedLock

三种模式:

  • 写锁
  • 悲观读锁
  • 乐观读

其中,写锁、悲观读锁的语义和 ReadWriteLock 的写锁、读锁的语义非常类似,允许多个线程同时获取悲观读锁,但是只允许一个线程获取写锁,写锁和悲观读锁是互斥的。

不同的是:StampedLock 里的写锁和悲观读锁加锁成功之后,都会返回一个 stamp;然后解锁的时候,需要传入这个 stamp。

主要方法:

  • long writeLock() ,阻塞式获取写锁
  • long tryWriteLock(),非阻塞式获取写锁,如果是0,表示没有拿到写锁
  • long tryWriteLock(long time, TimeUnit unit),同上,支持超时时间
  • long writeLockInterruptibly(),阻塞式获取写锁,支持中断
  • long readLock(),阻塞式获取悲观读锁
  • long tryReadLock(),非阻塞式获取悲观读锁,如果是0,表示没有拿到锁
  • long tryReadLock(long time, TimeUnit unit),同上
  • long readLockInterruptibly(),阻塞式获取悲观读锁,支持中断
  • long tryOptimisticRead(),获取乐观读的版本号
  • boolean validate(long stamp),验证上面的版本号是否通过,期间是否有修改
  • void unlockWrite(long stamp) ,释放写锁
  • void unlockRead(long stamp),释放悲观读锁
  • void unlock(long stamp),释放锁,笼统
  • long tryConvertToWriteLock(long stamp),升级读锁为写锁,非阻塞式,不满足返回0
  • 其它的一些方法,主要用于监控,数据采集

特性:

  • 不支持重入
  • 写锁、悲观读锁都不支持条件变量
  • 一定不要调用中断操作,如果需要支持中断功能,一定使用可中断的悲观读锁 readLockInterruptibly() 和写锁 writeLockInterruptibly()

与ReadWriteLock比较:

  • ReadWriteLock 支持多个线程同时读,但是当多个线程同时读的时候,所有的写操作会被阻塞,可能导致写的饥饿问题(读操作一直都能抢占到CPU时间片,而写操作一直抢不了)
  • StampedLock 的性能比 ReadWriteLock 好。主要是 StampedLock 支持乐观读的方式。当在乐观读期间,允许另一个线程获取写锁。那么怎样保证读和写的一致性呢?通过validate()方法,如果校验不通过,说明期间有修改,可以再重试一次。

乐观读,使用模板:

代码语言:javascript复制
final StampedLock sl =  new StampedLock();
 
// 乐观读
long stamp = sl.tryOptimisticRead();

// 读入方法局部变量
......
// 校验 stamp
if (!sl.validate(stamp)){
  // 升级为悲观读锁
  stamp = sl.readLock();
  try {
    // 读入方法局部变量
    .....
  } finally {
    // 释放悲观读锁
    sl.unlockRead(stamp);
  }
}
// 使用方法局部变量执行业务操作
......

0 人点赞