1. Предпосылки
В языке Java синхронизация потоков может быть достигнута с помощью Synchronized, т. е.замок. и достигаетПессимистический замок, сначала заблокируйте напрямую при работе с ресурсами синхронизации.
Блокировка может сделать часть кода доступной только для одного потока одновременно.При повышении безопасности производительность выполнения программы приносится в жертву.Поэтому, чтобы в определенной степени снизить потребление производительности, вызванное получением и освобождением После jdk6 были введены «предвзятые блокировки» и «облегченные блокировки», поэтому всего существует 4 состояния блокировки, уровни от низкого до высокого:Разблокированное состояние,Смещенное состояние блокировки,Легкое состояние блокировки,Статус тяжеловесной блокировки. Эти состояния будут постепенно обостряться с конкуренцией.
Примечание. Замки можно улучшать, но нельзя понижать.
Конечно, прежде чем говорить об этих четырех штатах, нам все еще нужно кратко понять принцип синхронизации.
При использовании synchronized для синхронизации блока кода он будет вставлен в начало блока кода после компиляции.директива monitorenter, вставьте инструкцию **monitorexit в конце или исключении. **Когда выполняется инструкция monitorenter, она попытается получить право собственности на **монитор**, соответствующий объекту, то есть попытается получить блокировку объекта. Блокировка, используемая синхронизацией, хранится вЗаголовок объекта Java середина.
Итак, вводятся два ключевых слова: «Заголовок объекта Java» и «Монитор».
2. Заголовок и монитор объекта Java
1. Заголовок объекта Java
Возьмем в качестве примера виртуальную машину Hotspot.Заголовок объекта Hotspot в основном включает в себя две части данных: Mark Word (отметить поле) и Klass Pointer (указатель типа).
Mark Word: HashCode, возраст генерации и информация о флаге блокировки объекта сохраняются по умолчанию. Вся эта информация представляет собой данные, не связанные с определением самого объекта, поэтому Mark Word разработан как нефиксированная структура данных, чтобы хранить как можно больше данных в очень небольшом пространстве памяти. Он будет повторно использовать свое собственное пространство для хранения в соответствии с состоянием объекта, то есть данные, хранящиеся в Mark Word, будут изменяться при изменении флага блокировки во время работы.
Klass Point: указатель объекта на его метаданные класса, и виртуальная машина использует этот указатель, чтобы определить, экземпляром какого класса является объект.
2. Монитор
Монитор можно понимать как инструмент синхронизации или механизм синхронизации, обычно описываемый как объект. Каждый объект Java имеет невидимую блокировку, называемую внутренней блокировкой или блокировкой монитора.
Монитор — это структура данных, приватная для потока, у каждого потока есть список доступных записей монитора, а также есть глобальный доступный список. Каждый заблокированный объект будет связан с монитором, и в мониторе есть поле «Владелец» для хранения уникального идентификатора потока, которому принадлежит блокировка, указывающего, что блокировка занята этим потоком.
Три, без замка
Без блокировки означает, что ресурс не заблокирован, все потоки могут получать доступ и изменять один и тот же ресурс, но только один поток может успешно изменять его одновременно.
Характеристика блокировки без блокировки заключается в том, что операция модификации будет выполняться в цикле, а поток будет постоянно пытаться изменить общий ресурс. Если конфликта нет, модификация завершается успешно и завершается, в противном случае цикл продолжит попытки. Если несколько потоков изменяют одно и то же значение, должен быть один поток, который может успешно изменить значение, а другие потоки, которым не удастся изменить значение, будут продолжать повторять попытки до тех пор, пока изменение не будет успешным.
4. Блокировка смещения
Предвзятая блокировка означает, что когда часть кода синхронизации всегда обращается к одному и тому же потоку, то есть когда нет конкуренции между несколькими потоками, тогда поток будет автоматически получать блокировку при последующих обращениях, тем самым уменьшая потребление, вызванное получением lock, то есть улучшить производительность.
Когда один поток для доступа к блокировке и получает блоки синхронизации, в Mark Word будет иметь тенденцию заблокировать в сохраненном идентификаторе потока. Когда нить больше не входит и выходит из синхронизированного блока, чтобы заблокировать и разблокировать операции CAS, но MARK Word обнаруживает, будет ли хранить в указывании на текущую резьбу потока блокировки. Время приобретения и выпуска зависит от легкого блокировки CAS атомных инструкций, но нужно только полагаться на смещенные блокирующие атомные инструкции CAS, могут быть заменены при потоке.
Смещенная блокировка снимает блокировку только тогда, когда другие потоки пытаются конкурировать за смещенную блокировку, и поток не будет активно снимать смещенную блокировку.
Что касается отзыва предвзятой блокировки, необходимо дождаться глобальной точки безопасности, то есть, когда в определенный момент времени нет исполняемого байт-кода, он сначала приостановит поток, которому принадлежит предвзятая блокировка, а затем определит, объект блокировки заблокирован. Если поток не активен, заголовок объекта устанавливается в состояние отсутствия блокировки, блокировка смещения отменяется и восстанавливается состояние блокировки без блокировки (флаг 01) или упрощенная блокировка (флаг 00).
Блокировка смещения включена по умолчанию в JDK 6 и более поздних версиях JVM. Смещенную блокировку можно отключить с помощью параметра JVM: -XX:-UseBiasedLocking=false, после закрытия программа по умолчанию войдет в состояние облегченной блокировки.
5. Легкий замок
Облегченная блокировка означает, что когда блокировка является смещенной блокировкой, к ней обращается другой поток.В это время смещенная блокировка будет обновлена до облегченной блокировки, а другие потоки будут вращаться через спин (см. конец статьи). для введения вращения) При попытке получить блокировку поток не будет блокироваться, что повышает производительность.
Приобретение упрощенных замков в основном происходит в двух случаях: ① Когда функция блокировки смещения отключена; ② Блокировка смещения модернизируется до облегченной блокировки из-за конкуренции нескольких потоков за блокировку смещения.
Когда код входит в синхронизированный блок, если состояние блокировки объекта синхронизации является состоянием без блокировки, виртуальная машина сначала создаст пространство с именем Lock Record в кадре стека текущего потока для хранения текущей метки блокировки. Копия Word, а затем Mark Word в заголовке объекта копируется в запись блокировки.
После успешного копирования виртуальная машина будет использовать операцию CAS, чтобы попытаться обновить слово метки объекта до указателя на запись блокировки и указать указатель владельца в записи блокировки на слово метки объекта.
Если операция обновления выполнена успешно, то поток владеет блокировкой объекта, а флаг блокировки объекта Mark Word устанавливается в «00», указывая на то, что объект находится в состоянии облегченной блокировки.
Если операция обновления облегченной блокировки не удалась, виртуальная машина сначала проверит, указывает ли Mark Word объекта на фрейм стека текущего потока.Если это так, это означает, что текущий поток уже владеет блокировкой объекта. , то он может напрямую войти в блок синхронизации для продолжения Execute, иначе это означает, что несколько потоков конкурируют за блокировку.
Если в настоящее время существует только один ожидающий поток, поток будет ожидать, вращаясь. Но когда вращение превышает определенное количество раз, облегченная блокировка будет повышена до тяжелой блокировки (раздувание блокировки).
Кроме того, когда поток уже удерживает блокировку, другой поток вращается, а в это время посещает третий поток, облегченная блокировка также будет обновлена до тяжелой блокировки (раздувание блокировки).
6. Тяжелый замок
Тяжеловесная блокировка означает, что когда один поток получает блокировку, все остальные потоки, ожидающие ее получения, будут заблокированы.
Тяжеловесная блокировка реализуется монитором внутри объекта, а суть монитора в том, чтобы полагаться на реализацию Mutex Lock базовой операционной системы.Операционная система должна переключаться из пользовательского режима в режим ядра для переключения между потоками , а стоимость переключения очень высока.
Короче говоря, все управление передается операционной системе, а операционная система отвечает за планирование между потоками и изменение состояния потоков. Таким образом, частое переключение рабочего состояния потока, приостановка и пробуждение потока, что потребляет большое количество системных ресурсов, приводит к низкой производительности.
7. О спине
Что касается спина, короче говоря, дайте треду отдохнуть с чашкой кофе.Объяснение кода:
do {
// do something
} while (自旋的规则,或者说自旋的次数)
Причина введения правила вращения на самом деле очень проста, потому что для блокировки или пробуждения потока Java требуется, чтобы операционная система переключила состояние ЦП на завершение, а этот переход состояния занимает процессорное время. Если содержимое блока синхронизированного кода слишком простое, переход между состояниями может занять больше времени, чем время выполнения пользовательского кода. И во многих сценариях время блокировки синхронных ресурсов очень мало, для такого короткого периода времени переключения потоков накладные расходы на эту часть операции на самом деле больше, чем выигрыш.
Следовательно, в случае физической машины с несколькими процессорами, когда два или более потока выполняются параллельно одновременно, мы можем позволить последнему потоку, запрашивающему блокировку, не уступать время выполнения ЦП, а смотреть на поток, удерживающий блокировку Будет ли блокировка снята в ближайшее время. А для того, чтобы заставить текущий поток «подождать момент», нам нужно заставить текущий поток вращаться. Если поток, ранее заблокировавший ресурс синхронизации, снял блокировку после завершения вращения, текущий поток может напрямую получить ресурс синхронизации без блокировки, тем самым избегая накладных расходов на переключение потоков.
Спин-блокировки по своей сути невыгодны, они не заменяют блокировку. Хотя ожидание вращения позволяет избежать накладных расходов на переключение потоков, оно потребляет процессорное время. Ожидание вращения работает очень хорошо, если блокировка удерживается в течение короткого периода времени. И наоборот, если блокировка удерживается в течение длительного времени, вращающийся поток будет только тратить ресурсы процессора.
Поэтому время ожидания спина должно иметь определенный предел.Если спин превышает лимитированное количество раз (по умолчанию 10 раз, для изменения можно использовать -XX:PreBlockSpin) и блокировка не получена успешно, нить следует приостановить.
Спин-блокировки были представлены в JDK1.4.2 и включены с помощью -XX:+UseSpinning . Он стал включен по умолчанию в JDK 6, и была введена адаптивная спин-блокировка (Adaptive Spinlock).
Адаптивная блокировка вращения означает, что время (количество раз) вращения больше не фиксировано, а определяется предыдущим временем вращения на том же замке и состоянием владельца замка. Если на том же объекте блокировки спин-ожидание только что успешно захватило блокировку, а поток, удерживающий блокировку, работает, то виртуальная машина будет думать, что этот спин, скорее всего, снова будет успешным, и разрешит спин. длится относительно дольше. Если вращение для определенной блокировки редко удается успешно, процесс вращения может быть пропущен при попытке получить блокировку в будущем, и поток будет заблокирован напрямую, чтобы избежать траты ресурсов процессора.
8. Резюме
Блокировка смещения решает проблему блокировки, сравнивая Mark Word и избегая выполнения операций CAS.
Легкая проблема блокировки блокировки решается с помощью операций CAS и спина, чтобы избежать блокировки потоков и влиять на производительность.
Тяжелый замок - заблокировать оба потока, кроме потока с замком.
Оригинальный адрес:woohoo.jet chen.can/synchronize…
Ссылаться на:Специальности.Meituan.com/2018/11/15/…