контур
предисловие
Пессимистическая блокировка и оптимистичная блокировка — частые вопросы на собеседованиях.
у нас должны быть некоторые понятия
пессимистический замокКак следует из названия, это пессимистическое убеждение, что, пока не будут приняты правильные меры по синхронизации, у него обязательно будут проблемы.
оптимистическая блокировкаЭто означает, что для синхронизации данных я оптимистично настроен на то, что без мер по синхронизации проблем не будет, но если есть проблемы, я приму меры по исправлению, такие как повторная попытка.
Механизм синхронизации между несколькими потоками в основном включаетчетыре
- Мьютекс
- критическая секция
- сигнал
- мероприятие
Давайте не будем говорить о разнице между этими четырьмя, просто помните, что 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.
- После JDK1.5 есть
выберите
Пессимистичные замки подходят для письма, оптимистичные — для чтения.
- Если операций записи много, будет много конфликтов потоков, поэтому выбирайте в это время пессимистичные блокировки; если много операций чтения, то конфликтов потоков будет меньше, и выбирайте в это время оптимистичные блокировки.
причина
- Есть много операций записи и много ресурсов конкуренции, CAS будет тратить ресурсы процессора из-за раскрутки.
- Больше операций чтения и меньше конкуренции за ресурсы
- Использование пессимистических блокировок блокирует потоки и переключает потоки между пользовательским режимом и режимом ядра (см. мою статью, Java и потоки)