В обмен на производительность JVM много оптимизирует встроенные блокировки, одной из которых является стратегия распределения блокировок с раздуванием. Понимание основных проблем, которые необходимо решить для предвзятых, облегченных и тяжеловесных блокировок, а также процессов распределения и расширения нескольких блокировок, поможет вам писать и оптимизировать параллельные программы на основе блокировок.
Процесс выделения и расширения встроенных замков относительно сложен, ограничен временем и усилиями.Эта часть контента в этой статье основана на интеграции многосторонней онлайн-информации; это только для удобства, а также ссылка при продолжении анализа исходного кода JVM. Если у вас уже есть общее представление о блокировках на всех уровнях, читатели могут пропустить эту статью.
Основная проблема, скрытая под встроенным замком
Встроенная блокировка — наиболее удобный инструмент синхронизации потоков, предоставляемый JVM.Вы можете использовать встроенную блокировку, добавив ключевое слово synchronized в блок кода или объявление метода. Использование встроенных блокировок может упростить модель параллелизма; с обновлением JVM вы можете напрямую пользоваться результатами оптимизации JVM для встроенных блокировок без изменения кода. От простых тяжеловесных блокировок до расширенных стратегий выделения блокировок — для решения фундаментальных проблем, скрытых за встроенными блокировками, используются различные оптимизации.
тяжелый замок
Встроенные блокировки абстрагируются в Java как блокировки монитора. До JDK 1.6 блокировки монитора можно было рассматривать как прямое соответствие мьютексам в базовой операционной системе. Стоимость этого метода синхронизации очень высока, включая переключение между режимом ядра и режимом пользователя, вызванное системными вызовами, и переключение потока, вызванное блокировкой потока. Поэтому такой замок позже назвали «тяжелым замком».
блокировка спина
Прежде всего, непросто оптимизировать переключение между режимом ядра и режимом пользователя. ноБлагодаря спин-блокировкам можно уменьшить переключение потоков, вызванное блокировкой потока.(включая приостановку и возобновление потоков).
Если степень детализации блокировки мала, тоВремя удержания блокировки относительно короткое(Хотя конкретное время удержания неизвестно, можно считать, что некоторые замки обычно соответствуют вышеперечисленным свойствам). Затем для тех, кто конкурирует за эти блокировки, время переключения потоков, вызванное блокировкой блокировки, эквивалентно времени удержания блокировки.Уменьшение переключения потоков, вызванного блокировкой потока, может значительно повысить производительность. детали следующим образом:
- Когда текущий поток не может конкурировать за блокировку, он намеревается заблокировать себя.
- Не блокировать себя напрямую, а вращать (пустое ожидание, например, пустой конечный цикл for) некоторое время
- Повторно соревнуйтесь за замок во время вращения
- Если блокировка получена до окончания вращения, то блокировка получена успешно, в противном случае она блокируется после окончания вращения.
Если блокировка снимается старым владельцем в течение времени вращения, то текущему потоку не нужно блокировать себя.(И не нужно восстанавливать, когда блокировка будет снята в будущем), уменьшая переключатель потока.
Условие удерживания блокировки в течение короткого времени можно ослабить. На самом деле, пока время конкуренции за блокировку относительно короткое (например, когда поток 1 собирается снять блокировку, поток 2 будет конкурировать за блокировку), вероятность получения блокировки путем вращения может быть повышена. Обычно это происходит, когдаБлокировка держится долго, но конкуренция не жесткаяв сцене.
недостаток
- На одноядерном процессоре фактического параллелизма нет.Если текущий поток не блокирует себя, старый владелец не может выполниться, и блокировка никогда не будет снята.В это время, какой бы продолжительной ни была спина, она Кроме того, если потоков много, а процессоров мало, спин также приведет к большому количеству ненужных потерь.
- Спин-блокировки занимают ЦП. Если это задача, требующая больших вычислительных ресурсов, эта оптимизация обычно не стоит выигрыша. Лучше сократить использование блокировок.
- Если время борьбы за блокировку относительно велико, спин обычно не может получить блокировку, и время ЦП, занимаемое циклом, тратится впустую. Обычно это происходит, когдаБлокировки держатся долго и конкуренция жесткаяВ сценарии спин-блокировка в это время должна быть активно отключена.
Используйте параметр -XX:-UseSpinning, чтобы отключить оптимизацию спин-блокировки; параметр -XX:PreBlockSpin, чтобы изменить количество спинов по умолчанию.
Адаптивная блокировка спина
Адаптивный означает, что время вращения больше не является фиксированным, а определяется предыдущим временем вращения на том же замке и состоянием владельца замка:
- Если на том же объекте блокировки спин-ожидание только что успешно заблокировало блокировку, а поток, удерживающий блокировку, работает, то виртуальная машина будет думать, что этот спин, скорее всего, снова будет успешным, и разрешит цикл ожидания. относительно более длительный период времени, например, 100 петель.
- Наоборот, если вращение редко удается успешно получить для определенной блокировки, можно будет уменьшить время вращения или даже пропустить процесс вращения при получении блокировки в будущем, чтобы избежать пустой траты ресурсов процессора.
Адаптивный спин решает проблему «неопределенного времени конфликта блокировки». JVM трудно определить точное время конфликта блокировки, и предоставление его пользователю для анализа нарушает исходное намерение JVM.Адаптивное вращение предполагает, что разные потоки удерживают один и тот же объект блокировки почти одинаковое время, а уровень соревнования стремится быть стабильным, поэтому время следующего вращения может быть скорректировано в соответствии со временем и результатом предыдущего вращения..
недостаток
Однако адаптивный спин полностью не решил эту проблему.Если установка числа вращений по умолчанию является необоснованной (слишком высокой или слишком низкой), адаптивному процессу будет трудно сходиться к подходящему значению..
Легкий замок
Целью спиннинга является снижение стоимости переключения потоков. Если конкуренция между блокировками жесткая, мы должны полагаться на блокировку-тяжеловес, пусть конкурирующие потоки отказоустойчивости; если реальной конкуренции блокировок нет, то блокировка уровня веса приложения тратится впустую.Целью облегченных замков является снижение производительности при использовании тяжелых замков без реальной конкуренции., в том числе переключение между режимом ядра и режимом пользователя, вызванное системными вызовами, переключение потока, вызванное блокировкой потока, и т. д.
Как следует из названия, легкие замки относятся к тяжелым замкам. При использовании облегченной блокировки нет необходимости применять мьютекс, просто _обновить часть байтов в CAS Mark Word до Lock Record в стеке потоков, если обновление прошло успешно, облегченная блокировка получена успешно_, запись статус блокировки — облегченная блокировка;В противном случае это означает, что поток уже получил облегченную блокировку, и произошла конкуренция блокировок (продолжать использовать облегченную блокировку нецелесообразно), и тогда она расширится до тяжеловесной блокировки..
Слово Mark является частью заголовка объекта; каждый поток имеет свой собственный стек потоков (стек виртуальной машины), который записывает основную информацию о потоках и вызовах функций. Оба относятся к основному содержанию JVM и не будут здесь представлены.
Конечно, поскольку легкие замки, естественно, направлены на сценарии, где нет конкуренции блокировки, если есть конкуренция замка, но не ожесточенная, спиновые замки все еще могут использоваться для оптимизации.Сбой в вращении снова превращается в тяжеловесный замок.
недостаток
Аналогично спин-блокировкам:
- еслиКонкуренция за замки жесткая, то облегченный замок быстро превратится в тяжеловесный, и процесс обслуживания легковесного замка станет расточительством.
Блокировка смещения
При отсутствии реальной конкуренции он также может продолжать оптимизацию для некоторых сценариев. Если нет не только фактической конкуренции, но и есть только один поток, использующий блокировку от начала до конца, то поддержка легковесных блокировок расточительна.Цель предвзятых блокировок — снизить потребление производительности при использовании облегченных блокировок, когда нет конкуренции и только один поток использует блокировку.. Облегченным блокировкам требуется по крайней мере один CAS каждый раз, когда они применяют и освобождают блокировки, но смещенные блокировки требуют только один CAS для инициализации.
«Предпочтение» означает,Предвзятые блокировки предполагают, что только первый поток, применяющийся для блокировки, будет использовать блокировку в будущем.(ни одна нить не будет применяться для блокировки снова), поэтому,Нужно только записать владельца CAS в Mark Word (по сути, он тоже обновляется, но начальное значение пустое), если запись удалась, то и получение смещения блокировки прошло успешно., статус блокировки записи является предвзятой блокировкой,В дальнейшем, если текущий поток равен владельцу, блокировка может быть получена напрямую с нулевой стоимостью, в противном случае это означает наличие других конкурирующих потоков, которые расширятся до легковесной блокировки..
Смещенные блокировки не могут быть оптимизированы с помощью спин-блокировок, потому что, как только для блокировки применяется другой поток, предположение о смещенных блокировках нарушается.
недостаток
Точно так же смещенные блокировки быстро превратятся в облегченные блокировки, если очевидно, что на блокировку претендуют другие потоки.
Но этот побочный эффект намного меньше.
При желании отключите оптимизацию смещенной блокировки с помощью параметра -XX:-UseBiasedLocking (по умолчанию включено).
резюме
Подробные процедуры для блокировок со смещением, упрощенных блокировок, распределения тяжеловесных блокировок и надувания приведены ниже. Потребуется некоторое знание Mark Word и CAS.
Предвзятые блокировки, легкие блокировки и тяжелые блокировки подходят для различных сценариев параллелизма:
- Предвзятая блокировка: фактической конкуренции нет, и только первый поток, подавший заявку на блокировку, будет использовать блокировку в будущем.
- Облегченные блокировки: реальной конкуренции нет, несколько потоков используют блокировки поочередно; разрешена краткосрочная конкуренция блокировок.
- Блокировка в тяжелом весе: настоящее соревнование, а время соревнования по замку долгое.
Кроме того, если время конфликта блокировки невелико, спин-блокировки можно использовать для дальнейшей оптимизации производительности облегченных и тяжеловесных блокировок и уменьшения переключения потоков.
Если уровень конкуренции за блокировки увеличивается постепенно (медленно), то постепенный переход от предвзятых блокировок к взвешенным блокировкам может повысить общую производительность системы.
Блокировка распределения и процесса инфляции
Повторюсь, эта часть в основном основана на нескольких источниках в Интернете. Ядро этогигантОрганизованная блок-схема довольно подробная и в основном логичная.
Выше описаны некоторые основные проблемы и решения при использовании встроенных замков, а также кратко упомянуты принципы реализации. Подробный процесс выделения и расширения блокировки выглядит следующим образом:
На картинке вопрос:
Согласно процессу, показанному на рисунке,Если вы обнаружите, что блокировка превратилась в тяжеловесную блокировку, используйте мьютекс, чтобы напрямую заблокировать текущий поток..
Однако одним из больших преимуществ спин-блокировок является уменьшение накладных расходов на переключение потоков. Здесь нет необходимости напрямую блокировать текущий поток, это может быть как легковесная блокировка, крутиться какое-то время, а затем блокироваться в случае неудачи.
Особенно два момента:
- Когда CAS регистрирует владельца,
expected == null
,newValue == ownerThreadId
,следовательно,Только первый поток, который применил смещенную блокировку, может вернуть успех, а последующие потоки должны завершиться ошибкой.(Часть потока обнаруживает, что он может быть предвзятым, и пытается зарегистрировать владельца с помощью CAS). - Встроенные блокировки могут только постепенно расширяться в порядке смещения замков, облегченных замков и тяжелых замков., не может "сжиматься". Это основано на другом допущении JVM».Как только предположение о блокировке верхнего уровня нарушено, считается, что это предположение не должно выполняться в будущем.".
Кроме того, при снятии тяжеловесной блокировки необходимо пробудить заблокированный поток.Эта часть логики в основном такая же, как и у ReentrantLock.Подробнее см.Исходный код | ReentrantLock и AQS (1) параллельного цветка: блокировка, разблокировка.
упрощенная версия
Вышеприведенная картинка очень подробная, а в Mark Word есть и схемы. Разобравшись с приведенным выше рисунком, посмотрите на упрощенную версию блок-схемы в «Углубленное понимание виртуальной машины Java: расширенные функции и рекомендации JVM (второе издание)», чтобы понять:
Выкопать яму:
Упрощенная версия гласит, что
重偏向
процесс. Этот процесс очень важен как для оптимизации производительности, так и для процесса инфляции, но если принять во внимание сильное смещение, приведенное выше специальное утверждение может оказаться неверным. Слишком много заметок для систематизации и не хватает времени, поэтому Monkey решила временно отказаться от этой проблемы.Ссылка на роль тяжелого уклона и эпохи:
Ссылаться на:
Ссылка на эту статью:Говоря о замке смещения, легком замке, тяжелом замке
автор:обезьяна 007
Источник:monkeysayhi.github.io
Эта статья основана наCreative Commons Attribution-ShareAlike 4.0Выпущено по международному лицензионному соглашению, приветствуется перепечатка, вывод или использование в коммерческих целях, но авторство и ссылка на эту статью должны быть сохранены.