如何使用StampedLock乐观锁定?(我无法理解Java文档中的代码示例)

gst*_*low 3 java concurrency multithreading locking stampedlock

最近我了解了存在StampedLock吗?

https://docs.oracle.com/javase/10/docs/api/java/util/concurrent/locks/StampedLock.html 我意识到它是改进的ReentrantReadWriteLock,具有一些区别:

  • 不重入
  • 支持虚拟锁
  • 支持从readLock升级到writeLock

我也阅读了frpm javadoc的示例,但我并不理解该代码:

class Point {
  private double x, y;
  private final StampedLock sl = new StampedLock();
  // a read-only method
  // upgrade from optimistic read to read lock
  double distanceFromOrigin() {
    long stamp = sl.tryOptimisticRead();
    try {
      retryHoldingLock: for (;; stamp = sl.readLock()) {
        if (stamp == 0L)
          continue retryHoldingLock;
        // possibly racy reads
        double currentX = x;
        double currentY = y;
        if (!sl.validate(stamp))
          continue retryHoldingLock;
        return Math.hypot(currentX, currentY);
      }
    } finally {
      if (StampedLock.isReadLockStamp(stamp))
        sl.unlockRead(stamp);
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

这是什么意思possibly racy reads?[在评论中回答]

如果另一个线程读取x或是一个问题y吗?[在评论中回答]

为什么在tryOptimisticRead失败的情况下先执行tryOptimisticRead并在for循环中执行readLock?逻辑是什么?

为什么我们在 if (StampedLock.isReadLockStamp(stamp))内部在解锁之前最终阻止vbe?

Joh*_*int 8

为什么在tryOptimisticRead失败的情况下先执行tryOptimisticRead并在for循环中执行readLock?逻辑是什么?

最好的情况下是我们能够阅读xy无需获得锁。这并不意味着我们不建立先发生后关系,而是意味着我们不需要调用可能的阻止动作。

tryOptimisticRead返回我们的邮票价值。这种volatile内部状态的读取确定了在此标记值的易失性写入之前写入的任何内容在随后的读取之后将可见。这意味着,如果tryOptimisticRead在您读取x和时返回的标记值没有变化y,则不会发生另一次写入,并且我们拥有最新的值。但是,如果盖印的值确实发生了变化,则所有投注都将关闭,您需要保护自己,如下所述。

根据您的用例,这种可能性是有可能的,x并且y在您执行的整个过程中都会有所改变distanceFromOrigin。如果x并且y改变,并且可能经常改变,那么您将要最终成功。

readLock程序的意思是“好吧,我放弃,让我们以一种阻塞的方式阅读它”。从理论上讲,您可以tryOptimisticRead在最终调用之前编写几次代码readLock,但是您将想以防万一xy并不断进行更新。

为什么我们在内部如果if(StampedLock.isReadLockStamp(stamp))最终阻止vbefore解锁?

如果readLock被调用,则必须在退出之前将其释放,以便后续writeLock用户可以获得该锁。如果您成功了tryOptimisticRead,则不必发布a,readLock因为您根本不需要先获得它。