Как использовать оптимистическую блокировку StampedLock? (Я не могу понять пример кода из документа Java) - PullRequest
3 голосов
/ 19 апреля 2019

Недавно я узнал о существовании 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);
    }
  }
}

Что это значит possibly racy reads?[ОТВЕТСТВЕННО В КОММЕНТАРИИ]

Есть ли проблема, если другой поток читает x или y?[ОТВЕТСТВЕННО В КОММЕНТАРИЯХ]

Почему мы сначала выполняем tryOptimisticRead и readLock в цикле for в случае сбоя tryOptimisticRead?что за логика?

Почему у нас есть if (StampedLock.isReadLockStamp(stamp)) внутри блока наконец перед разблокировкой?

1 Ответ

8 голосов
/ 23 апреля 2019

почему мы сначала выполняем tryOptimisticRead и readLock в цикле for в случае сбоя tryOptimisticRead? в чем логика?

В лучшем случае мы сможем читать x и y без необходимости блокировки. Это не значит, что мы не устанавливаем отношения «происходит раньше», это просто означает, что нам не нужно вызывать возможное блокирующее действие.

tryOptimisticRead возвращает нам значение штампа. Это volatile чтение внутреннего состояния устанавливает, что все, что написано до изменчивой записи этого штампованного значения, будет видно после последующего чтения . Это означает, что если значение с меткой, возвращенное в tryOptimisticRead, не изменяется, пока вы читаете x и y, то другой записи не произошло, и у нас есть самые последние значения. Однако, если значение с печатью действительно меняется, все ставки отменены, и вам необходимо защитить себя, как описано ниже.

Возможно, и, в зависимости от вашего варианта использования, вполне вероятно, что x и y будут меняться в какой-то момент на протяжении всего выполнения distanceFromOrigin. Если x и y изменятся и, возможно, будут часто меняться, вы захотите в конечном итоге добиться успеха.

readLock - это способ программы сказать: «Хорошо, я сдаюсь, давайте просто прочитаем его блокирующим образом». Теоретически, вы можете написать свой код в tryOptimisticRead несколько раз, прежде чем в конечном итоге вызвать readLock, но вы захотите выдать себя, если x и y будут постоянно обновляться.

Почему у нас, если (StampedLock.isReadLockStamp (stamp)) внутри блока finally перед разблокировкой?

Если вызывается readLock, вам придется отпустить его до выхода, чтобы последующие writeLock могли получить блокировку. Если вы преуспеете в tryOptimisticRead, вам не нужно будет выпускать readLock, так как вам вообще не нужно было его приобретать.

...