В механизме параллельной реализации Java большинство контейнеров и фреймворков реализованы с использованием изменчивых/синхронизированных/атомарных операций.Понимание лежащего в основе механизма параллелизма очень поможет параллельному программированию.
Во-первых, применение синхронизированного
Synchronized уже является ветераном многопоточного параллельного программирования, и его часто называют тяжеловесной блокировкой. Поскольку это широко используемая блокировка, вам необходимо иметь глубокое понимание ее базовой реализации.
1. Принцип реализации синхронизированного
Когда поток обращается к блоку синхронизированного кода, он должен сначала получить блокировку объекта в блоке кода, а когда он выходит или создает исключение, он должен снять блокировку. Реализация синхронизации synchronized заключается в том, что JVM реализует синхронизацию методов и синхронизацию блоков кода на основе объекта Monitor, входящего и выходящего из объекта синхронизации.
Каждый объект «Монитор» имеет связанный с ним монитор, и он заблокирован тогда и только тогда, когда монитор удерживается. Синхронный код реализуется с помощью директив monitorenter и monitorexit. Инструкция monitorenter вставляется в начало синхронизированного блока кода после компиляции кода, а инструкция monitorexit вставляется в конец метода и в исключение. Когда поток выполняет команду monitorenter, он попытается получить право собственности на монитор объекта, то есть попытается получить блокировку объекта.
2. Форма употребления и значение слова синхронизированный
- Модифицированный обычный метод: блокировка - это текущий объект экземпляра
- Украсьте статический метод: блокировка — это объект класса текущего класса.
- Модифицированный кодовый блок: замок представляет собой объект, настроенный в синхронизированных скобках.
3. Блокировка обновления
Существует четыре состояния блокировки: состояние без блокировки -> состояние смещенной блокировки -> облегченное состояние блокировки -> тяжелое состояние блокировки.
Блокировка смещения:Когда поток обращается к синхронизированному блоку и получает блокировку, он сохраняет идентификатор смещения блокировки в записи блокировки в заголовке объекта и игле стека.Позднее потоку не нужно использовать операции CAS для блокировки и выхода при входе и выход из синхронизированного блока.Операция разблокировки, но нужно только проверить, является ли идентификатор потока, хранящийся в поле Mark Word в заголовке объекта, текущим потоком. Если да, то это означает, что блокировка получена успешно, если нет, то необходимо проверить, установлено ли в поле предвзятой блокировки в заголовке объекта значение 1 (что указывает на то, что текущая блокировка является предвзятой блокировкой). , вам нужно использовать CAS, чтобы конкурировать за получение блокировки. Если установлено, попробуйте использовать CAS, чтобы указать смещенный идентификатор блокировки заголовка объекта на текущий поток.
Легкий замок;
- Облегченная блокировка блокировки: прежде чем поток выполнит синхронизированный блок, он сначала создает пространство для хранения записи блокировки в своем собственном стеке потока и назначает слово метки в объекте записи блокировки. Затем поток пытается использовать операцию CAS для замены Mark Word в заголовке объекта указателем на запись блокировки. Если это удается, это означает, что текущий поток получает блокировку, если это не удается, это означает, что другие потоки также конкурируют за блокировку, и текущий поток получает блокировку в цикле.
- Разблокировка облегченной блокировки: при разблокировке облегченной блокировки будет использоваться атомарная операция CAS для замены записи блокировки заголовком объекта.В случае успеха это означает, что конкуренция отсутствует. Если это не удается, это означает, что текущая блокировка конкурирует, и блокировка увеличивается до тяжеловесной блокировки.
4. Сравнение замков
тип замка | преимущество | недостаток | Применимая сцена |
---|---|---|---|
тяжелый замок | Конкуренция потоков не использует вращение и не тратит ресурсы ЦП | Блокировка потока, медленное время отклика | В погоне за пропускной способностью сценарии, в которых синхронизированное выполнение блоков занимает много времени |
Легкий замок | Конкурирующие потоки не будут блокироваться, что улучшит скорость отклика программы. | Если поток не получает блокировку в течение длительного времени, то вращение — это пустая трата ресурсов процессора. | Погоня за временем отклика, синхронизированная скорость выполнения блока высокая |
Блокировка смещения | Блокировка и разблокировка не требуют дополнительного потребления ресурсов | Если между потоками существует конкуренция, это приведет к дополнительному потреблению снятия блокировки. | Подходит только для одного сценария синхронизации доступа к потоку |
Во-вторых, применение летучих
Volatile — это облегченная синхронизация.Volatile обеспечивает видимость общих переменных в многопоточной разработке.Так называемая видимость означает, что, когда поток изменяет общую переменную, другие потоки могут прочитать значение модификации.
1. Определение и принцип реализации энергозависимой
volatile определение: язык программирования Java позволяет потокам получать доступ к общим переменным.Чтобы гарантировать, что общие переменные могут быть обновлены точно и последовательно, потоки должны гарантировать, что переменная получена через монопольную блокировку.
Принцип реализации: когда операция записи выполняется для переменной, объявленной как volatile, JVM отправит процессору инструкцию с префиксом блокировки для записи данных строки кэша, в которой находится переменная, обратно в системную память. В то же время, в случае нескольких процессоров, необходимо реализовать протокол когерентности кеша, то есть каждый процессор должен проверять, не истек ли срок действия его собственного кеша, путем прослушивания данных, распространяемых по шине. соответствует его собственной строке кэша. Когда адрес изменяется, строка кэша текущего процессора становится недействительной. Когда процессору необходимо работать с этими данными, данные считываются из системной памяти в строку кэша.
2. Два принципа реализации volatile
- Инструкции с префиксом Lock вызывают запись кэша процессора обратно в память;
- Кэш одного процессора записывается обратно в память, что делает недействительными кэши других процессоров.
В-третьих, принцип работы атома
см. статью[Серия параллельных программ] Класс атомарных операций в Java