StampedLock

2021/01/05 posted in  并发工具

读多写少的场景中,还有没有更快的技术方案,Java 在 1.8 这个版本里,提供了一种叫 StampedLock 的锁,它的性能就比读写锁还要好。

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);
}

乐观读

在多个线程同时读的时候,允许一个线程获取读锁,不是所有的写操作都被阻塞



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 注意事项

  1. 不支持重入
  2. 悲观读锁和写锁都不支持条件变量
  3. 如果线程阻塞在readLock和writeLock,此时调用该线程的interrupt,会导致CPU飙升
  4. 如果要支持中断功能,可中断的悲观读锁readLockInterruptibly()和写锁的writeLockInterruptibly()