StampedLock:有没有比读写锁更快的锁?

在读多写少的场景中,StampedLock比ReadWriteLock性能要好。

Why?

StampedLock 支持的三种锁模式
ReadWriteLock 支持两种模式:一种是读锁,一种是写锁。而 StampedLock 支持三种模 式,分别是:写锁、悲观读锁和乐观读。StampedLock 的性能之所以比 ReadWriteLock 还要好,其关键是 StampedLock 支持乐观读的方式。ReadWriteLock 支持多个线程同时读,但是当多个线程同时读的时候,所有的写操作会被阻塞;而 StampedLock 提供的乐观读,是允许一个线程获取写锁的,也就是说不是所有的写操作都被阻塞。
注意这里,我们用的是“乐观读”这个词,而不是“乐观读锁”,是要提醒你,乐观读这个操作是无锁的,所以相比较 ReadWriteLock 的读锁,乐观读的性能更好一些。

How?

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 性能很好,简单的应用场景基本上可以替代 ReadWriteLock,但是StampedLock 的功能仅仅是 ReadWriteLock 的子集,在使用的 时候,还是有几个地方需要注意一下。
1 StampedLock 不支持重入。
2 StampedLock 的悲观读锁、写锁都不支持条件变量。
3 使用 StampedLock 一定不要调用中断操作,如果需要支持中断功能,一定使用可 中断的悲观读锁 readLockInterruptibly() 和写锁 writeLockInterruptibly()。

锁的升级和降级

StampedLock 支持锁的降级(通过 tryConvertToReadLock() 方法实现)和升级(通过 tryConvertToWriteLock() 方法实现),但使用时要慎重。
下面的代码也源自 Java 的官方示例

private double x, y;
final StampedLock sl = new StampedLock();
void moveIfAtOrigin(double newX, double newY){
 long stamp = sl.readLock();
 try {
  while(x == 0.0 && y == 0.0){
    long ws = sl.tryConvertToWriteLock(stamp);
    if (ws != 0L) {
      x = newX;
      y = newY;
      //如果升级锁成功,tryConvertToWriteLock(stamp)这个方法内部会释放悲观读锁stamp。但是写锁需要主动释放。
      stamp = ws;
      break;
    } else {
      sl.unlockRead(stamp);
      stamp = sl.writeLock();
    }
  }
 } finally {
  sl.unlock(stamp);
}

你可能感兴趣的:(StampedLock:有没有比读写锁更快的锁?)