Пессимистическая блокировка и оптимистичная блокировка

Java

контур

предисловие

Пессимистическая блокировка и оптимистичная блокировка — частые вопросы на собеседованиях.

у нас должны быть некоторые понятия

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

оптимистическая блокировкаЭто означает, что для синхронизации данных я оптимистично настроен на то, что без мер по синхронизации проблем не будет, но если есть проблемы, я приму меры по исправлению, такие как повторная попытка.

Механизм синхронизации между несколькими потоками в основном включаетчетыре

  • Мьютекс
  • критическая секция
  • сигнал
  • мероприятие

Давайте не будем говорить о разнице между этими четырьмя, просто помните, что Synchronized использует мьютекс операционной системы.


Все мои статьи обновляются синхронно с Github--Java-Notes, Если вы хотите узнать о JVM (в основном более полной), анализе исходного кода HashMap, связанных с пружинами, параллелизме, решении проблемы с предложением (версия Java), вы можете нажать звездочку. Вы можете увидеть мою домашнюю страницу на github, которая обновляется каждый день.

Приглашаю вас завершить репо со мной


Взаимоисключающая (блокирующая) синхронизация - пессимистическая блокировка

Взаимное исключение является лишь одним из средств механизма синхронизации, а также очень распространенным средством обеспечения корректности параллелизма.

Мы знаем, почему традиционные блокировки (например, synchronized или reentrantLock) называютсятяжелый замок, потому что он используетМьютекс ОСсинхронизировать

synchronized

Это метод, с которым мы наиболее знакомы. Обычно, когда новички изучают синхронизацию, мы используем это ключевое слово, но этот метод используетсемафор операционной системы, так что эффективность относительно низкая

Synchronized в Java может реализовать основы синхронизации:Объекты в Java можно использовать в качестве замков

Три формы:

  • Обычный метод синхронизации, экземпляр объекта блокировки
  • Статический метод синхронизации, замок — это объект Class текущего класса
  • Для блоков синхронизированных методов объект конфигурации в скобках заблокирован.

Принцип реализации

JVM основана на входе и выходеобъект наблюденияДля достижения синхронизации методов и синхронизации блоков кода

При синхронизации ключевое словосоставленоПосле этого он будет сформирован до и после синхронизированного блока (где начинается и заканчивается синхронизированный блок кода или где возникает исключение)monitorenterа такжеmonitorexitДве инструкции байт-кода.

  • Каждому входу монитора должен соответствовать выход монитора. При выполнении команды monitorenter счетчик блокировки увеличивается на единицу, соответственно при выполнении команды monitorexit счетчик уменьшается на единицу.Когда счетчик достигает 0, блокировка снимается
  • Синхронизированный блок является реентерабельным для одного и того же потока и не блокируется.
  • Синхронизированный блок блокирует доступ других потоков до тех пор, пока вошедший поток не завершит выполнение.

Спецификация метода синхронизации не указывает, но метод синхронизации также может быть реализован с помощью двух вышеуказанных инструкций.

ReentrantLock

В базовом использовании ReentrantLock очень похож на Synchronized.

По сравнению с Synchronized ReentrantLock добавляет следующие функции:

  • дождаться прерываемого
    • Как следует из названия, ожидающий поток может отказаться от ожидания и вместо этого заняться другими делами.
    • Полезно для синхронизированных блоков, выполнение которых занимает много времени.
  • Справедливая блокировка может быть достигнута
    • Что такое справедливость?первый пришел первыйСчитайте один, тот, кто подал заявку первым, получит ее первым, и порядок получения замков отсортирован в соответствии с порядком, в котором замки были поданы.
    • А вот недобросовестных блокировок, типа Synchronized, нет, они случайные
    • ReentrantLock также является несправедливой блокировкой по умолчанию, но справедливая блокировка может быть реализована через конструктор с логическим значением.
  • Блокировки могут связывать несколько условий
    • Это означает, что объект ReentrantLock может одновременно связывать несколько объектов Condition,
    • В Synchronized методы wait() и notify() или notifyAll() объекта блокировки могут реализовывать неявное условие. Если вы хотите связать более одного условия, вам нужно добавить дополнительную блокировку
    • ReentrantLock не нужно этого делать, просто вызовите метод newCondition() несколько раз.

выберите

В последней версии оптимизация для Synchronized очень велика, и производительность не сильно отличается от производительности ReentrantLock, поэтому, если вы не используете эти расширенные функции, рекомендуется использовать synchronized. Ведь Synchronized будет оптимизирован в будущем.

Ниже приведено сравнение производительности двух под JDK8 (первый самовозрастающий, последний представляет собой связанный список)

Неблокирующая синхронизация — оптимистическая блокировка

Оптимистическая блокировка не требуетсяТема висит в ожидании, так еще называютнеблокирующая синхронизация

Механизм номера версии

Как правило, поле версии добавляется в таблицу данных, чтобы указать, сколько раз данные были обновлены.изменить один раз, номер версииплюс один.

условие

Версия фиксации должна быть больше, чем текущая записанная версия

Например

Теперь у меня есть 10 юаней на моем банковском счете, и теперь есть поле версии с номером версии 1.

Теперь я вывожу 2 юаня операцией A, я сначала читаю в данных версию = 1, а затем вычитаю

В то же время операция B также берет 1 юань, считывает версию данных = 1, а затем вычитает

В это время операция A завершена, данные загружены, номер версии увеличен на единицу, версия = 2, эта версия больше, чем текущее значение записи 1, поэтому операция обновления завершена.

В это время также завершается операция B, и ее необходимо обновить, номер его версии увеличивается на единицу, версия = 2. Затем при обновлении обнаруживается, что этот номер версии совпадает с номером версии текущая запись.Не удовлетворяет то, что отправленный номер версии должен быть больше, чем текущая запись.Условие номера версии, обновление не разрешено

В это время операция B будет перечитана, и предыдущие шаги будут повторены.

С помощью этого метода мы гарантируем, что операция B не перезапишет значение, обновленное операцией A, обеспечивая синхронизацию данных.

CAS-алгоритм

Алгоритм CAS создается на основе разработки аппаратного обеспечения. Почему, ведь нам нужны эти два атомарных шага

  • действовать
  • обнаружение столкновений

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

  • протестировать и настроить
  • получить и добавить
  • обмен
  • Сравнить и поменять местами (CAS)
  • Загрузить ссылку/хранить условно (LL/SC)

Первые три — это инструкции, которые существовали очень давно, а последние две — это инструкции, которые есть только у современных процессоров.

шаг

CAS имеет три номера.

  • В, место памяти
  • А, старое значение
  • Б, новое значение

Тогда и только тогда, когда значение V совпадает со значением A, процессор будет использовать значение B для обновления значения в V; в противном случае он не выполняет обновление. (Вышеприведенное сравнение и обновление является атомарной операцией). Как правило, эта операциявращаться, то есть он будет продолжать попытки, пока не закончит

Недостатки CAS

  • АВА-проблема
    • Потому что он хочет сравнить, равны ли значение в V и значение в А (точнее, изменилось ли значение в V), но если оно равно, может ли это означать, что он не изменился? значение V Сначала может быть A, затем B, а затем снова A. Очевидно, что таким образом значения V и A равны, но они изменились.
    • Решение состоит в том, чтобы добавить к нему номер версии.
      • При каждом обновлении версия увеличивается на единицу.变成1A -> 2B -> 3A
      • После JDK1.5 есть этот классAtomicStampedReference, то вы можете использоватьcompareAndSetметод. Сначала он проверяет, является ли текущая ссылка ожидаемой ссылкой, а затем проверяет, равен ли текущий флаг ожидаемому флагу.
  • Длительное время цикла и высокие накладные расходы
    • Если CAS не удался, он продолжит потреблять производительность ЦП.
    • Если JVM может поддерживать предоставленный процессоромpauseИнструкции, производительность будет улучшена в определенной степени
      • Он может задерживать выполнение инструкций в конвейере, чтобы ЦП не потреблял слишком много ресурсов.
      • избегать при выходе из цикла, потому чтоконфликт порядка памятиЭто приводит к опорожнению трубопровода, что повышает производительность.
  • Только гарантированные атомарные операции над общей переменной
    • При манипулировании общей переменной можно использовать CAS
    • Если вы работаете с несколькими переменными, вам нужно использовать блокировку или объединить ее в одну переменную.
      • После JDK1.5 естьAtomicReferenceКласс, вы можете поместить несколько переменных в объект, чтобы использовать операции CAS.

выберите

Пессимистичные замки подходят для письма, оптимистичные — для чтения.

  • Если операций записи много, будет много конфликтов потоков, поэтому выбирайте в это время пессимистичные блокировки; если много операций чтения, то конфликтов потоков будет меньше, и выбирайте в это время оптимистичные блокировки.

причина

  • Есть много операций записи и много ресурсов конкуренции, CAS будет тратить ресурсы процессора из-за раскрутки.
  • Больше операций чтения и меньше конкуренции за ресурсы
    • Использование пессимистических блокировок блокирует потоки и переключает потоки между пользовательским режимом и режимом ядра (см. мою статью, Java и потоки)