Nano Hash - криптовалюты, майнинг, программирование

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

Недавно я узнал о существовании 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)) внутри finally block vbefore unlock ?


  • Возможно, колоритные чтения связаны с тем, что в первом цикле поток попытался оптимистично получить блокировку чтения, но, возможно, это не удалось. Если блокировка действительна (validate), то прочитанные значения безопасны, и он продолжает их использовать. В противном случае прочитанные значения небезопасны, и цикл продолжается, теперь получая блокировку чтения с помощью блокирующего метода readLock(). По крайней мере, я всегда так понимал эти примеры. 19.04.2019
  • @Slaw, это имеет смысл, но: это проблема, если другой поток читает x или y? 19.04.2019
  • Чтобы расширить комментарий @Slaw, javadoc для StampedLock в описании оптимистического чтения говорится: Поля, прочитанные в оптимистическом режиме, могут быть крайне противоречивыми, поэтому на этой первой итерации, если объект обновляется между вызовами tryOptimisticRead() и validate() значения currentX и currentY могут не совпадать. 19.04.2019
  • @gstackoverflow Нет, это проблема, если другой поток обновляет x или y. 19.04.2019
  • @Andreas, поэтому validate возвращает false, только если writeLock был получен после получения оптимистичной блокировки? 19.04.2019
  • @Slaw, почему мы сначала выполняем tryOptimisticRead и readLock в цикле for в случае сбоя tryOptimisticRead? 19.04.2019
  • Если оптимистическая блокировка не удалась, либо из-за того, что tryOptimisticRead() возвращает 0, либо из-за того, что validate() возвращает false, цикл повторяется (continue), чтобы получить полную блокировку чтения и снова запустить логику. Обратите внимание, что используется только третья часть оператора for, так что readLock() вызывается только на второй итерации. Также имейте в виду, что цикл будет выполняться один раз (оптимистическая блокировка успешна) или дважды (оптимистическая блокировка не удалась), но никогда не будет выполняться три раза. 19.04.2019
  • В Javadoc, в описании оптимистического чтения, говорится: Этот режим можно рассматривать как чрезвычайно слабую версию блокировки чтения, которую писатель может сломать в любой момент. Использование режима оптимистического чтения для коротких сегментов кода, предназначенных только для чтения, часто снижает количество конфликтов и повышает пропускную способность. Вы используете tryOptimisticRead(), потому что уверены, что значения не изменятся при их чтении. Но если они это сделают, вы обновитесь до полной блокировки чтения и продолжите. 19.04.2019
  • @Slaw, но его нельзя сломать с помощью readLock? 19.04.2019
  • С чего бы это? Блокировка чтения не является монопольной — это означает, что несколько потоков могут читать одновременно. 19.04.2019
  • @Slaw Я просто хотел подтвердить это. Таким образом, 2 потока могут выполнять оптимистическое чтение параллельно, а 2 других потока могут выполнять чтение одновременно. 19.04.2019
  • @Andreas, но какова логика этого фрагмента кода? Почему мы сначала пробуем оптимистическую блокировку, а потом уже обычную readLock. В чем преимущество такого подхода? 19.04.2019
  • Да, как и любая блокировка чтения-записи, блокировка чтения-записи не является монопольной, а блокировка записи-эксклюзивной; если есть писатель, читатели не могут продолжить. И это преимущество упоминается в Javadoc, который я цитировал: Использование режима оптимистического чтения для коротких сегментов кода, предназначенных только для чтения, часто снижает конкуренцию и повышает пропускную способность. Обратите внимание, что StampedLock не является заменой ReadWriteLock — используйте StampedLock только в том случае, если ваша структура данных применима и вы измерили прирост производительности. 19.04.2019
  • @ Slaw Использование режима оптимистического чтения для коротких сегментов кода, предназначенных только для чтения, часто снижает количество конфликтов и повышает пропускную способность. Когда это может помочь? Когда слишком много операций чтения, что мешает получить writeLock ? 19.04.2019
  • @gstackoverflow Да, это очень хороший пример. --- Кроме того, оптимистическая блокировка на самом деле не является блокировкой, так что вы также можете сэкономить время выполнения. 19.04.2019
  • Вы можете найти этот ответ и ссылки, которые он предоставляет, быть полезными: stackoverflow.com/a/26100951/6395627 19.04.2019
  • @Andreas Но, согласно моим экспериментам, writeLock всегда имеет более высокий приоритет: 1. В момент 0 мс Thread 1 получает readLock на 1 секунду 2. В момент 200 ms Thread 2 пытается получить writeLock и ожидает 3. В момент 500 ms Thread 3 пытается получить readLock и ожидает. Согласно моим экспериментам, поток 2 всегда получает writeLock после первого потока и перед потоком 3 readLock. 19.04.2019
  • @ Слава, прочитай, пожалуйста, обновление темы 20.04.2019
  • В документации прямо указано, что блокировки записи не предпочтительнее блокировок чтения и наоборот. А бит if (...) в блоке finally связан с тем, что отметка может не представлять собой блокировку чтения (т. е. она может представлять оптимистическую блокировку чтения). 20.04.2019
  • @Slaw, значит, для оптимистичной блокировки isReadLockStamp возвращает false? 20.04.2019

Ответы:


1

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

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

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

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

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

Почему у нас есть if (StampedLock.isReadLockStamp(stamp)) внутри finally block vbefore unlock ?

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

23.04.2019
  • отличное объяснение. 30.06.2021
  • Новые материалы

    Кластеризация: более глубокий взгляд
    Кластеризация — это метод обучения без учителя, в котором мы пытаемся найти группы в наборе данных на основе некоторых известных или неизвестных свойств, которые могут существовать. Независимо от..

    Как написать эффективное резюме
    Предложения по дизайну и макету, чтобы представить себя профессионально Вам не позвонили на собеседование после того, как вы несколько раз подали заявку на работу своей мечты? У вас может..

    Частный метод Python: улучшение инкапсуляции и безопасности
    Введение Python — универсальный и мощный язык программирования, известный своей простотой и удобством использования. Одной из ключевых особенностей, отличающих Python от других языков, является..

    Как я автоматизирую тестирование с помощью Jest
    Шутка для победы, когда дело касается автоматизации тестирования Одной очень важной частью разработки программного обеспечения является автоматизация тестирования, поскольку она создает..

    Работа с векторными символическими архитектурами, часть 4 (искусственный интеллект)
    Hyperseed: неконтролируемое обучение с векторными символическими архитектурами (arXiv) Автор: Евгений Осипов , Сачин Кахавала , Диланта Хапутантри , Тимал Кемпития , Дасвин Де Сильва ,..

    Понимание расстояния Вассерштейна: мощная метрика в машинном обучении
    В обширной области машинного обучения часто возникает необходимость сравнивать и измерять различия между распределениями вероятностей. Традиционные метрики расстояния, такие как евклидово..

    Обеспечение масштабируемости LLM: облачный анализ с помощью AWS Fargate и Copilot
    В динамичной области искусственного интеллекта все большее распространение получают модели больших языков (LLM). Они жизненно важны для различных приложений, таких как интеллектуальные..