4. Принцип синхронизированной реализации
4.1 Synchronization
Synchronization in the Java Virtual Machine is implemented by monitor entry and exit, either explicitly (by use of the monitorenter and monitorexit instructions) or implicitly (by the method invocation and return instructions).
For code written in the Java programming language, perhaps the most common form of synchronization is the synchronized method. A synchronized method is not normally implemented using monitorenter and monitorexit. Rather, it is simply distinguished in the run-time constant pool by the ACC_SYNCHRONIZED flag, which is checked by the method invocation instructions (§2.11.10).
- Этот абзац взят изThe Java® Virtual Machine Specification 3.14. Synchronization
- В JVM синхронизация достигается за счет входа и выхода из блокировок монитора либо явно с помощью инструкций monitorenter и monitorexit, либо неявно с помощью инструкций вызова метода и возврата.
- Возможно, наиболее распространенной реализацией синхронизации для кода Java является синхронизированный метод. Блок кода синхронизации реализуется с помощью monitorenter и monitorexit, а метод синхронизации неявно реализуется с помощью тега ACC_SYNCHRONIZED, принцип заключается в проверке наличия в методе тега ACC_SYNCHRONIZED в пуле констант через инструкцию вызова метода.
- В этой статье не будет анализироваться реализация Synchronized с помощью байт-кода, но это всего лишь точка.Заинтересованные читатели могут обратиться кСинхронизированная реализация анализа исходного кода JVM(Конечно, если есть шанс открыть JVM, автор проведет повторный анализ)
4.2 Декомпиляция
4.2.1 Подготовка
Чтобы интуитивно понять принцип работы Synchronized, мы можем посмотреть, что получилось, декомпилировав class-файл класса SynchronizedDeme.
package concurrent;
public class SynchronizedDemo {
public static synchronized void staticMethod() throws InterruptedException {
System.out.println("静态同步方法开始");
Thread.sleep(1000);
System.out.println("静态同步方法结束");
}
public synchronized void method() throws InterruptedException {
System.out.println("实例同步方法开始");
Thread.sleep(1000);
System.out.println("实例同步方法结束");
}
public synchronized void method2() throws InterruptedException {
System.out.println("实例同步方法2开始");
Thread.sleep(3000);
System.out.println("实例同步方法2结束");
}
public static void main(String[] args) {
final SynchronizedDemo synDemo = new SynchronizedDemo();
Thread thread1 = new Thread(() -> {
try {
synDemo.method();
} catch (InterruptedException e) {
e.printStackTrace();
}
});
Thread thread2 = new Thread(() -> {
try {
synDemo.method2();
} catch (InterruptedException e) {
e.printStackTrace();
}
});
thread1.start();
thread2.start();
}
}
4.2.1 Создание файла .class
javac SynchronizedDemo.java
Примечание: Поскольку кодировка по умолчанию в ОС автора - UTF-8, могут возникать следующие ошибки
Решение следующее: просто пройти-encodingУкажите указанный метод кодирования
javac -encoding UTF-8 SynchronizedDemo.java
В итоге мы получим.class файл, т.е.SynchronizedDemo.class
4.2.2 декомпиляция javap
javap -v SynchronizedDemo
Благодаря декомпиляции мы получим разные результаты компиляции пула констант, метода синхронизации и блока кода синхронизации, а затем представим их на основе этих трех
Диаграмма постоянного пула
В дополнение к примитивным типам и постоянным значениям для строк и массивов пул констант также содержит символьные ссылки в текстовом виде:
- Полные имена классов и интерфейсов
- Имена полей и дескрипторы
- Методы, имена и дескрипторы
Схема метода синхронизации
Синхронизированные методы будут содержать флаг ACC_SYNCHCRONIZED.
Блок-схема синхронизированного кода
Блоки синхронизированного кода вставляют в код директивы monitorenter и monitorexist.
4.3 Принцип блочной синхронизации кода синхронизации
4.3.1 монитор монитор
- Каждый объект имеет монитор.В блоке кода синхронизации JVM реализует функции получения и снятия блокировки синхронизации с помощью инструкций monitorenter и monitorexist.
- Когда поток получает блокировку синхронизации, это эквивалентно получению блокировки путем получения монитора монитора.
- Реализация монитора аналогична процессу монитора в операционной системе.
4.3.2 команда мониторинтер
Each object is associated with a monitor. A monitor is locked if and only if it has an owner. The thread that executes monitorenter attempts to gain ownership of the monitor associated with objectref, as follows:
• Если количество входов монитора, связанного с objectref, равно нулю, поток входит в монитор и устанавливает свой счетчик входов равным 1. Поток становится владельцем монитора.
• Если потоку уже принадлежит монитор, связанный с objectref, он повторно входит в монитор, увеличивая свой счетчик входов.
• Если другой поток уже владеет монитором, связанным с objectref, поток блокируется до тех пор, пока счетчик записей монитора не станет равным нулю, а затем снова пытается завладеть им.
- Каждый объект имеет монитор. Когда монитор занят, он блокируется (или получение монитора — это получение блокировки синхронизации). Когда поток выполняет команду monitorenter, он попытается получить право собственности на монитор.Процесс выглядит следующим образом:
- Если счетчик записей монитора равен 0, поток входит в монитор и устанавливает счетчик записей равным 1, а поток является владельцем монитора.
- Если поток уже владеет монитором и является реентерабельным, количество записей +1
- Если другие потоки уже владеют монитором, поток будет заблокирован до тех пор, пока количество записей монитора не станет равным 0, после чего потоки будут конкурировать за право владения монитором.
- Только поток, который первым получил блокировку, может продолжать получать несколько блокировок.
4.3.3 команда выхода из монитора
The thread that executes monitorexit must be the owner of the monitor associated with the instance referenced by objectref.
The thread decrements the entry count of the monitor associated with objectref. If as a result the value of the entry count is zero, the thread exits the monitor and is no longer its owner. Other threads that are blocking to enter the monitor are allowed to attempt to do so.
- Выполнение команды monitorexit будет состоять из следующих шагов:
- Поток, выполняющий команду monitorexit, должен быть владельцем монитора, соответствующего экземпляру объекта.
- При выполнении инструкции поток сначала установит количество записей равным -1.Если количество записей станет равным 0 после -1, поток выйдет из монитора (т. е. снимет блокировку).
- Другие потоки, заблокированные на мониторе, могут повторно конкурировать за право владения монитором.
4.3.4 Принцип реализации
- В блоке кода синхронизации JVM реализует функции получения и снятия блокировки синхронизации с помощью инструкций monitorenter и monitorexist.
- Директива monitorenter вставляется в начало синхронизированного блока кода после компиляции.
- Инструкция monitorexit вставляется в конец метода и в исключение
- JVM должна гарантировать, что каждый вход монитора должен быть сопряжен с соответствующим выходом монитора.
- Любой объект имеет связанный с ним монитор, и когда монитор удерживается, он будет заблокирован
- Когда поток выполняет команду monitorenter, он попытается получить право собственности на монитор, соответствующий объекту, то есть попытается получить блокировку объекта.
- Когда поток выполняет команду monitorexit, он освобождает монитор, когда число записей равно -1, пока оно не станет равным 0.
- Только один поток может быть успешным одновременно, другие потоки, которые не работают, будут заблокированы, помещены в очередь синхронизации и перейдут в состояние BLOCKED.
4.3.4 Дополнение
- Сведения об объектных ссылках см. в разделе Как использовать блокировки.
- Поскольку базовая реализация таких методов, как ожидание/уведомление, основана на мониторах, такие методы, как ожидание/уведомление, можно вызывать только в синхронизированных методах (блоках), в противном случаеjava.lang.IllegalMonitorStateException причина исключения
4.4 Принцип синхронизации метода синхронизации
- В отличие от реализации монитора синхронизированных блоков кода, синхронизированные методы неявно реализуются с помощью флага ACC_SYNCHRONIZED.
- Принцип состоит в том, чтобы проверить, содержит ли метод флаг ACC_SYNCHRONIZED в пуле констант через инструкцию вызова метода, и если да, то JVM требует, чтобы поток запрашивал блокировку перед вызовом
5. Расширенный принцип
5.1 Объектный режим монитора
5.1.1 Обзор объектного режима монитора
- Монитор на самом деле является средством синхронизации, его также можно назвать механизмом синхронизации, его обычно описывают как объект, основные черты - взаимоисключение и сигнальный механизм
- Взаимоисключающий:Блокировка монитора может быть занята только одним потоком одновременно, другие потоки не могут ее занимать.
- Сигнальный механизм (сигнал):Поток, который не может занять блокировку монитора, временно отказывается от участия в соревновании и ждет, пока предикат станет истинным (условная переменная), но после того, как условие будет установлено, текущий поток уведомит другие потоки, ожидающие эту условную переменную, освобождая замок, так что он может повторно конкурировать за замок
Сигнальный механизм Месы
- Сигнальный механизм Mesa также называется «Неблокирующая условная переменная».
- Когда поток, удерживающий блокировку монитора, выдает уведомление об освобождении, он не потеряет блокировку немедленно, а позволит другим потокам ждать в очереди и снова конкурировать за блокировку.
- В этом механизме после того, как официант получает блокировку, невозможно определить, вошли ли другие официанты в Монитор в течение этой разницы во времени, поэтому нет гарантии, что предикат должен быть истинным, поэтому суждение об условии должно использоваться в то время как
- В Java используется единый механизм Mesa, так называемый notify.
5.1.2 Структура объектного режима монитора
В паттерне Monitor Object существует четыре основных типа участников:
5.1.3 Процесс совместной работы в объектном режиме монитора
1. Вызов и сериализация синхронных методов:
- Когда клиентский поток вызывает метод синхронизации объекта монитора, вы должны сначала получить его блокировку монитора.
- Операция get не будет успешной, пока в объекте-наблюдателе выполняются другие синхронизированные методы.
- Когда объект-наблюдатель уже занят потоком (т. е. выполняется синхронизированный метод), клиентский поток будет заблокирован до тех пор, пока не получит блокировку-наблюдателя.
- Когда клиентский поток успешно получает блокировку монитора, он входит в критическую секцию и выполняет службу, реализованную методом
- Как только синхронизированный метод завершает выполнение, блокировка монитора автоматически снимается, чтобы дать другим клиентским потокам возможность вызвать синхронизированный метод, который выполняет объект монитора.
2. Поток метода синхронизации приостановлен:Если клиентский поток, вызывающий синхронизированный метод, должен быть заблокирован или не может продолжить работу немедленно по другим причинам, он может ожидать состояния монитора (условия монитора), что приведет к тому, что клиентский поток временно освободит блокировку монитора и будет приостановлен в состоянии монитора. начальство
3. Уведомления о состоянии мониторинга:Клиентский поток может уведомить о состоянии монитора, цель состоит в том, чтобы уведомить поток, заблокированный в состоянии монитора (блокировка монитора), чтобы возобновить работу
4. Синхронный метод восстановления потока:
- Как только поток синхронизированного метода, который ранее был приостановлен из-за состояния наблюдения, получает уведомление, он возобновляет выполнение в точке, где он первоначально ожидал условия наблюдения.
- Прежде чем уведомленному потоку будет разрешено возобновить выполнение синхронизированного метода, блокировка монитора будет автоматически получена (потоки автоматически конкурируют друг с другом за блокировки).
Для монитора автор подробно расскажет в статье ReentractLock.
5.2 Заголовок объекта
5.2.1 Объекты в памяти JVM
- В JVM расположение объектов в памяти разделено на три области: заголовок объекта, демонстрационные данные и заполнение выравнивания.
- Заголовок объекта:Заголовок объекта в основном хранит хэш-код объекта, информацию о блокировке, указатель типа, длину массива (если это массив) и другую информацию.
- Пример данных:Храните информацию об атрибутах класса, включая информацию об атрибутах родительского класса. Если это часть экземпляра массива, она также включает длину массива. Эта часть памяти выравнивается по 4 байтам.
- Ввод данных:Поскольку JVM требует, чтобы начальный адрес объекта был целым числом, кратным 8 байтам, он будет автоматически заполнен, когда он не соответствует 8 байтам (поэтому данные заполнения не нужны, только для выравнивания байтов)
5.2.2 Обзор заголовка объекта
- Синхронизированная блокировка хранится в заголовке объекта Java.
- Если объект является типом массива, JVM использует 3 подширины (Word) для хранения заголовка объекта, в противном случае он использует 2 подширины.
- В 32-битной виртуальной машине 1 sub-width равен 4 байтам или 32 битам, в 64-битных — 8 байтам или 64 битам.
5.2.3 Структура хранения Mark Word
Структура хранения Mark Word по умолчанию для 32-разрядной JVM (состояние без блокировки)
Во время работы данные, хранящиеся в Mark Word, будут изменяться при изменении флага блокировки (32 бита).
Структура хранения Mark Word по умолчанию для 64-битной JVM (для 32-битного безблокировочного состояния 25 бит не используются)
5.3 Monitor Record
5.3.1 Обзор записи монитора
- MonitorRecord (сокращенно MR) — это структура данных, приватная для потоков Java.Каждый поток имеет список доступных MR, а также глобальный список доступных MR.
- Заблокированный объект будет связан с MR (LockWord в MarkWord заголовка объекта указывает на начальный адрес MR)
- В MR есть поле Owner, в котором хранится уникальный идентификатор потока, владеющего блокировкой, указывающий, что блокировка занята этим потоком
5.3.2 Структура записи монитора
5.3.3 Рабочий механизм Monitor Record
- Если поток успешно получает блокировку монитора, он становится владельцем объекта блокировки монитора.
- В любой момент объект монитора принадлежит только одному активному потоку (владельцу).
- Владелец может вызвать метод ожидания, чтобы автоматически снять блокировку мониторинга и войти в состояние ожидания.
6. Оптимизация блокировки
6.1 Спин-блокировки
- Болевые точки:Поскольку для блокировки/пробуждения потоков требуется, чтобы ЦП переключался между режимом пользователя и режимом ядра, частые переключения сильно нагружают ЦП, что, в свою очередь, оказывает большое влияние на одновременную производительность.
- Феномен:В результате большого анализа было обнаружено, что состояние блокировки объекта обычно длится только в течение короткого периода времени, и нет необходимости часто блокировать и пробуждать поток.
- принцип:Позвольте потоку подождать какое-то время, выполнив бессмысленный пустой цикл, он не будет немедленно приостановлен, и посмотрите, скоро ли поток, удерживающий блокировку, освободит блокировку.Получите блокировку, тем самым уменьшив количество переключений и улучшив производительность.
- Скрытая опасность:Если блокировку можно снять быстро, то эффективность отжима очень хорошая (чем меньше количество фактических вращений, тем выше эффективность и меньше время ожидания); но если блокировка удерживается все время, то отжим не на самом деле не делает ничего значимого. Тем не менее, он напрасно занимает и тратит ресурсы ЦП, но это приводит к трате ресурсов.
- Уведомление:Количество вращений должно иметь ограничение (или время вращения).Если блокировка не будет получена после количества вращений (времени), оно будет заблокировано и приостановлено.
- использовать:-XX:+UseSpinning включен по умолчанию в JDK1.6 и выше, количество вращений можно настроить с помощью -XX:PreBlockSpin, по умолчанию 10 раз
6.2 Адаптивная спин-блокировка
- Болевые точки:Поскольку блокировка спина может указывать только фиксированное количество спинов, но из-за различий в задачах оптимальное количество спинов каждый раз разное.
- принцип:Вводя понятие «интеллектуального обучения», количество вращений определяется временем предыдущего вращения на том же замке и состоянием держателя замка, другими словами, количество вращений не фиксировано, но Вы можете получить в следующий раз, проанализировав прошлый раз, умнее
- выполнить:Если текущий поток успешно выполняет блокировку, следующий цикл может увеличиться в это время (поскольку JVM считает, что этот успех является основой для следующего успеха), и вероятность успеха может быть выше, если она увеличивается; в любом случае, если вращение редко удается, тогда количество вращений будет уменьшено (уменьшение потерь на холостом ходу) или даже пропущен процесс вращения напрямую и блокировка напрямую (потому что вращение совершенно бессмысленно, лучше сразу блокировать)
- Пополнить:С адаптивной спиновой блокировкой, с постоянным улучшением работы программы и информации о мониторинге производительности, JVM будет становиться все более и более точным в прогнозировании состояния блокировки, а JVM будет становиться все более и более интеллектуальным.
6.3 Блокирующие замки
6.3.1 Блокировка замков
- Успешно заблокировано:Когда возникает конфликт за блокировку, только поток, получивший блокировку, может продолжать выполняться.
- Не удалось заблокировать:Потоки, которые не могут конкурировать, перейдут в состояние блокировки из состояния выполнения и будут помещены в очередь ожидания, связанную с целевой блокировкой.
- Разблокировать:Когда поток, удерживающий блокировку, выходит из критической секции, после освобождения блокировки он разбудит заблокированный поток в очереди ожидания и заставит его повторно участвовать в соревновании блокировок.
- Пополнить:В этой статье не будет анализа конкретных моделей JVM, заинтересованные читатели могут ознакомиться с анализом HotSopt JVM.Углубленный механизм блокировки JVM 1-синхронный
6.3.2 Честная блокировка
Справедливая блокировка – это порядок, в котором блокировки получаются в порядке очереди. С точки зрения реализации требуется, чтобы, когда поток соревнуется за блокировку объекта, до тех пор, пока очередь ожидания блокировки не заполнена. не пустой, поток должен быть заблокирован и поставлен в очередь Хвост (хвост очереди вставки обычно поддерживается операцией CAS без снятия блокировки в процессе вставки)
6.3.3 Несправедливые блокировки
Напротив, в случае несправедливых блокировок каждый поток должен сначала конкурировать за блокировку и будет помещен в очередь ожидания только в том случае, если конкуренция не удалась или в настоящее время заблокирована. войти в очередь ожидания, чтобы напрямую конкурировать за блокировку (случайность)
6.4 Огрубление блокировки
- Болевые точки:Операции блокировки и разблокировки, которые соединяются вместе много раз, вызовут
- принцип:Объединяйте операции блокировки и разблокировки, которые соединяются вместе несколько раз, в одну и расширяйте несколько последовательных блокировок в блокировку с большим диапазоном.
- использовать:Сожмите несколько синхронизированных блоков рядом друг с другом в один синхронизированный блок или объедините несколько синхронизированных методов в один метод.
- Пополнить:Во встроенных API JDK, таких как StringBuffer, Vector и HashTable, есть операции неявной блокировки, которые можно комбинировать.
/**
* StringBuffer是线程安全的字符串处理类
* 每次调用stringBuffer.append方法都需要加锁和解锁,如果虚拟机检测到有一系列连串的对同一个对象加锁和解锁操作,就会将其合并成一次范围更大的加锁和解锁操作,即在第一次append方法时进行加锁,最后一次append方法结束后进行解锁
*/
StringBuffer stringBuffer = new StringBuffer();
public void append(){
stringBuffer.append("kira");
stringBuffer.append("sally");
stringBuffer.append("mengmeng");
}
6.5 Устранение блокировки
- Болевые точки:В соответствии с технологией выхода кода, если решено, что в фрагменте кода данные в куче не будут выходить из текущего потока, то этот код можно считать потокобезопасным и блокировки не нужны.
- принцип:JVM удаляет блокировки, которые вряд ли будут иметь конкуренцию за общие ресурсы, описывая текущий контекст во время компиляции, и устраняет таким образом бесполезные блокировки, то есть удаляет ненужные операции блокировки, тем самым экономя накладные расходы.
- использовать:Анализ выхода и снятие блокировок можно включить с помощью параметров -XX:+DoEscapeAnalysis и -XX:+EliminateLocks соответственно (удаление блокировок должно быть в режиме -server)
- Пополнить:Во встроенных API JDK, таких как StringBuffer, Vector и HashTable, есть операции неявной блокировки, которые можно исключить.
/**
* 比如执行10000次字符串的拼接
*/
public static void main(String[] args) {
SynchronizedDemo synchronizedDemo = new SynchronizedDemo();
for (int i = 0 ; i < 10000 ; i++){
synchronizedDemo.append("kira","sally");
}
}
public void append(String str1,String str2){
//由于StringBuffer对象被封装在方法内部,不可能存在共享资源竞争的情况
//因此JVM会认为该加锁是无意义的,会在编译期就删除相关的加锁操作
//还有一点特别要注明:明知道不会有线程安全问题,代码阶段就应该使用StringBuilder
//否则在没有开启锁消除的情况下,StringBuffer不会被优化,性能可能只有StringBuilder的1/3
StringBuffer stringBuffer = new StringBuffer();
stringBuffer.append(str1).append(str2);
}/**
6.6 Модернизация замков
- Начиная с JDK1.6, блокировка имеет четыре состояния:безблокировочное состояние,Смещенное состояние блокировки,Легкое состояние блокировки,Статус блокировки веса
- Состояние блокировки будет постепенно обостряться по мере раздора,Блокировка позволяет повышать, но не понижать
- Цель запрета понижения версии — повысить эффективность получения и снятия блокировок.
- Позже автор объяснит это в обратном порядке, то есть тяжелые блокировки -> легкие блокировки -> предвзятые блокировки, потому что обычно это оптимизация первых
Заблокировать процесс обновления
6.7 Тяжелый замок
- Тяжеловесные блокировки реализуются через монитор внутри объекта (см. паттерн Monitor Object выше).
- Суть монитора зависит от реализации MutexLock базовой операционной системы.Переключение между потоками операционной системы завершается переключением между пользовательским режимом и режимом ядра, и стоимость переключения очень высока.
- Основная концепция MutexLock заключается в том, чтобы попытаться получить блокировку. Если вы можете ее получить, возьмите ее, если не можете, идите спать и ждите.
- Заинтересованные читатели могут прочитатьГоворя о Mutex (Lock), эта статья дает хорошее объяснение MutexLock в Liunx.
6.8 Легкие замки
6.8.1 Обзор облегченных замков
- Болевые точки:Поскольку для блокировки/пробуждения потоков требуется, чтобы ЦП переключался между режимом пользователя и режимом ядра, частые переключения сильно нагружают ЦП, что, в свою очередь, оказывает большое влияние на одновременную производительность.
- Главная цель:В условиях отсутствия многопоточной конкуренции уменьшите потребление производительности традиционными тяжеловесными блокировками с помощью мьютексов операционной системы.
- Когда обновлять:Когда функция смещенной блокировки отключена или смещенная блокировка конкурирует между несколькими потоками, смещенная блокировка будет обновлена до облегченной блокировки.
- принцип:Дальнейшее улучшение производительности, когда только один поток выполняет синхронизированные блоки.
- структура данных:включаютуказатель на запись блокировки в стеке,замок флаг
- Пополнить:Читателям рекомендуется прочитать главу 8 «Углубленное понимание виртуальной машины JVM», посвященной фрейму стека, связанному со знанием механизма выполнения байт-кода виртуальной машины.
6.8.2 Блок-схема облегченной блокировки
Поток 1 и поток 2 одновременно конкурируют за блокировку, в результате чего блокировка становится тяжеловесной.
6.8.3 Замок с облегченным замком
- 1. Перед тем, как поток выполнит синхронизированный блок, JVM сначала создаст пространство для хранения записи блокировки в кадре стека текущего потока и скопирует Mark Word в заголовке объекта в запись блокировки (Displaced Mark Word — это есть замененное пометочное слово). Пометить слово) сделать копию
- 2. После успешного копирования поток пытается с помощью CAS заменить слово метки заголовка объекта указателем на запись блокировки (обновить слово метки заголовка объекта указателем на запись блокировки и указать Указатель владельца в записи блокировки на слово метки объекта)
- Если обновление прошло успешно, текущий поток получает блокировку и продолжает выполнять синхронизированный метод.
- Если обновление не удается, это означает, что другие потоки конкурируют за блокировку, а текущий поток пытается использовать вращение, чтобы получить блокировку. текущий поток будет заблокирован
6.8.4 Разблокировка упрощенной блокировки
- Когда разблокировано, слово Displaced Mark Word будет заменено обратно на заголовок объекта с помощью операции CAS,
- Если разлочка прошла успешно, значит конкуренции нет
- Если разблокировка не удалась, то это означает, что текущая блокировка конкурирует, и блокировка расширится до тяжеловесной блокировки.Необходимо разбудить заблокированный поток при освобождении блокировки, а затем потоки должны повторно конкурировать за тяжеловесную блокировку. замок в соответствии с правилами тяжеловесных замков.
6.8.5 Примечания к облегченным замкам
- Скрытая опасность:Существует предпосылка для использования облегченных блокировок, что «многопоточная конкурентная среда не существует». После того, как эта предпосылка будет нарушена, в дополнение к накладным расходам на взаимное исключение будут добавлены дополнительные накладные расходы на операции CAS. среда, легкие замки Даже медленнее, чем тяжелые замки
6.9 Блокировка смещения
6.9.1 Обзор блокировок смещения
- Болевые точки:Автор точки доступа найден вВ большинстве случаев нет многопоточной конкуренции, ноОдин и тот же поток получает одну и ту же блокировку несколько раз, чтобы удешевить получение блокировок потоками, разработаны смещенные блокировки (это во многом связано с использованием в бизнесе)
- Главная цель:Чтобы свести к минимуму ненужные облегченные пути выполнения блокировки без конкуренции за многопоточность.
- принцип:Дальнейшее повышение производительности за счет сокращения операций CAS путем добавления проверки флагов, когда только один поток выполняет синхронизированный блок.
- структура данных:включаютИдентификатор потока, удерживающий блокировку,Это нестандартный замок?,эпоха (временная метка смещена в сторону блокировки),возраст генерации объекта,замок флаг
6.9.2 Блок-схема блокировки смещения
Поток 1 демонстрирует процесс инициализации смещенной блокировки, а поток 2 демонстрирует процесс отзыва смещенной блокировки.
6.9.3 Инициализация блокировки смещения
- Когда поток получает доступ к синхронизированному блоку и получает блокировку, онСохраняйте идентификаторы потоков с блокировкой в записях блокировки в заголовках объектов и кадрах стека., позже, когда поток входит и выходит из синхронизированного блокаНе нужно тратить CAS-операции на блокировку и разблокировку, но сначала простоПроверяем, сохраняется ли поток в MarkWord заголовка объекта:
- Если он был сохранен, это означает, что поток получил блокировку и может продолжать выполнение задачи.
- Если он не сохранен, вам потребуетсяОпределить, является ли текущая блокировка смещенной блокировкой(то есть установлен ли флаг блокировки смещения в заголовке объекта в 1, а бит флага блокировки равен 01):
- еслинет настройки,ноИспользование CAS для борьбы за блокировки(Указывая, что в настоящее время это не предвзятая блокировка, это должна быть блокировка с более высоким уровнем, чем она)
- еслинастраивать, тогдаПопытка использовать CAS, чтобы указать предвзятую блокировку заголовка объекта на текущий поток, который является идентификатором потока в структуре
6.9.4 Блокировка отзыва блокировки с предвзятостью
- Блокировка смещения с помощьюПодождите, пока не возникнет конфликт, прежде чем снимать блокировку.Механизм, который удерживает смещенную блокировку, снимает блокировку только тогда, когда другие потоки конкурируют за блокировку.
- склонен к блокировкеОтзыв требует ожидания глобальной точки сохранения(в этот момент байт-код не выполняется)
- Для отзыва предвзятых блокировок необходимо выполнить следующие шаги:
сначала будетПриостановите поток, которому принадлежит смещенная блокировка, и проверьте, жив ли поток.:
- если нитьнеактивное состояние, тоЗаголовок объекта находится в разблокированном состоянии(Другие потоки повторно получат смещенную блокировку)
- если нитьАктивный статус, стек со смещенной блокировкой будет выполнен, проходя запись блокировки смещенного объекта, иЗапись блокировки в стеке и MarkWord заголовка объекта будут сброшены:
- илиПереориентация на другие темы(Смещенная блокировка передается другим потокам, что эквивалентно тому, что текущий поток «снимает» блокировку)
- иливернуться к безблокировкеилиОтметить объекты блокировки не подходят в качестве смещенных блокировок(В настоящее время замок будет модернизирован до легкого замка)
Наконец, разбудите приостановленный поток, и поток, заблокированный в безопасной точке, продолжит выполнение синхронизированного блока кода.
6.9.5 Смещенный замок для закрытия замка
- Блокировка смещения включена по умолчанию в JDK1.6 и выше и будет активирована через несколько секунд после запуска программы.
- Необходимо отключить задержку параметром JVM -XX:BiasedLockingStartupDelay=0
- Если определено, что блокировка обычно находится в конкурентном состоянии, смещенную блокировку можно отключить параметром JVM -XX:-UseBiasedLocking=false, тогда по умолчанию будет введена облегченная блокировка.
6.9.6 Меры предосторожности при блокировке смещения
- Преимущество:Смещенная блокировка должна полагаться только на атомарную инструкцию CAS при замене ThreadID, а в остальное время инструкция CAS не требуется (по сравнению с другими блокировками).
- Скрытая опасность:Так как пристрастная блокировка должна быть отозвана в случае многопоточной конкуренции, потеря производительности операции отзыва пристрастной блокировки должна быть меньше, чем потребление производительности сохраненными атомарными инструкциями CAS (обычно это можно узнать только по большому количеству операций). стресс-тесты)
- В сравнении:Облегченные блокировки предназначены для повышения производительности, когда потоки поочередно выполняют синхронизированные блоки, в то время как смещенные блокировки предназначены для дальнейшего повышения производительности, когда только один поток выполняет синхронизированные блоки.
6.10 Смещенные замки против облегченных замков против тяжелых замков
Добро пожаловать в колонку"Идти в ногу с Java 8", делитесь превосходными руководствами и учебными пособиями по китайскому языку Java8 и приветствуйте высококачественные статьи.
Синхронизированный паспорт (версия 1.8) Зависит от Хуан Чжипэн Кира создавать, использовать Creative Commons Attribution-NonCommercial 4.0 Международная лицензияЛицензия.