Мы знаем, что параллельные операции, реализованные Java, должны быть окончательно завершены нашим процессором. Тем временем мы собрали исходный код Java в файл .class, затем загружены, а затем выполняли механизм выполнения виртуальной машины, интерпретируемый как язык сборки, затем преобразуется в инструкции по операционной системе, а затем преобразован в 1, 0 и, наконец, процессор распознается и выполняется.
Когда мы упоминаем о параллелизме Java, мы не можем не думать об общих ключевых словах в Java: летучие и синхронизированные. Далее мы проанализируем их из этих двух слов отключения:
Основной принцип реализации летучих
Принципы реализации и приложения синхронизированных
нестабильный
Говоря о нестабильном, интервьюер - любимый вопрос, который нужно задать в интервью Java. Когда мы видим это, первое, о чем мы думаем, - это поддерживать видимость между потоками. Это легкий синхронизированный, который в некоторых случаях может заменить синхронизированный.
Роль нестабильной:
Для переменной, измененной летучей моделью, модель памяти Java обеспечит согласованность значения переменных, наблюдаемые всеми потоками.
Как работает летучие:
Мы можем определить летучую переменную, назначить ее значения и использовать инструменты для получения инструкций сборки, сгенерированных компилятором JIT. Мы обнаружим, что при записи в изменчивую переменную будет дополнительная инструкция: инструкция с префиксом с помощью блокировки:
Инструкция с префиксом блокировки приводит к тому, что две вещи возвращают к многоядерному процессору:
① Запишите данные текущей линии кэша процессора в память.
② Эта операция памяти записи будет аннулировать адрес памяти к кэшированию данных в других процессорах.
Когда мы знаем два вышеупомянутых пункта, нам не сложно понять механизм переменной Volatie.
В рамках нескольких процессоров, чтобы гарантировать, что кэш каждого процессора будет согласован, будет реализован протокол согласованности кэша. Каждый процессор обнюхивает распространенные данные на шине, чтобы проверить, истек ли кэшированное значение.
синхронизированный
Размышляя о многопоточной параральности, первое, о чем я думаю, это синхронизировано. Перевод как синхронизация. Мы все знаем, что это тяжелый замок. При использовании его для метода или кодового блока, когда поток получает этот блокировка, другие потоки попадут в подвешенное состояние, которое появится в состоянии сна в Java. Мы все знаем, что приостановка и время выполнения потока должны быть перенесены в состояние ядра операционной системы (соответствующее состоянию ядра является пользовательское состояние), которое особенно расточительно зависит от ресурсов процессора, поэтому этот тяжелый замок является настоящим!
Однако после Java SE 1.6 команда по техническому обслуживанию Java выполнила серию оптимизаций (эти оптимизации обсуждаются один за другим), так что это не так «тяжелый», и замок Reentrant, который имел преимущества в прошлом, стало менее выгодным (reentrantlock).
Давайте поговорим о синхронизированном в следующих аспектах:
Основы синхронизации для достижения синхронизации
Как синхронизированные орудия блокировки
Положительный замок, легкий замок (спин блокировка), тяжелый замок
Обновление блокировки
Как реализовать атомные операции на Java
① Основы синхронизации для достижения синхронизации:
Мы можем видеть синхронизированный в разработке или в исходном коде Java, такой как Hashtable, StringBuilder и другие места. Есть два распространенных способа:
Ⅰ, метод синхронизации
Метод синхронизации должен быть синхронизирован только перед методом. Когда один поток выполняет его, другие потоки попадут в ожидание, пока он не выпустит замок. Использование методов можно разделить на два типа: для обычных методов синхронизации и для статических методов. Разница между ними заключается в том, что заблокированные объекты разные. Заблокированное положение обычных методов - текущий объект, а заблокированное положение статических методов - это объект класса текущего класса.
Ⅱ, Блок метода синхронизации
Блок метода синхронизации блокирует объект, настроенный в кронштейнах после синхронизации. Этот объект может быть значением и любой переменной или объектом.
② How Synchronized реализует блокировку:
В спецификации JVM вы можете увидеть принцип реализации синхронизации в JVM. JVM реализует синхронизацию методов синхронизации и блоков кода на основе ввода и выхода из объекта монитора. Кодовый блок реализован с использованием инструкций Monitorenter и Monitorexit. Метод синхронизации конкретно не указан в спецификации JVM. Однако я считаю, что конкретные принципы должны быть разными. Это не что иное, как компиляция исходного кода Java в файл класса и маркировка синхронизированного метода в файле байт -кода класса. Этот метод будет синхронизирован, когда двигатель ByteCode выполняет этот метод.
③ Замок
Прежде чем говорить о замках, нам нужно знать заголовок объекта Java и заголовок объекта Java:
Замок, используемый синхронизированным, хранится в заголовке объекта Java. Заголовок объекта Java имеет 32 -битный/64 -битный (в зависимости от количества бит операционной системы). В Markword есть 2 -битные пространства для представления состояния блокировки 00, 01, 10, 11 соответственно, представляющих легкие замки, блокировки смещения, замки в тяжелом весе и следы GC.
Положительный блокировка: положительный блокировка называется эксцентричной блокировкой. От имени мы видим, что это замок, который стремится к определенной потоке.
В фактической разработке мы обнаружили, что многопоточная параленичность, большинство методов синхронизации выполняются одним и тем же потоком, а вероятность множества потоков, конкурирующих за один метод, является относительно низким, поэтому повторное получение и выброс замков вызовет множество отходов ресурсов. Следовательно, чтобы привлечь потока получить замок по более низкой стоимости, вводится блокировка смещения. Когда поток обращается к блоку синхронизации и получает блокировку, идентификатор потока блокировки смещения будет сохранен в записи блокировки в кадре стека заголовка объекта и потока. В будущем, когда поток входит и выходит из блока синхронизации, ей не нужно выполнять операции CAS, чтобы заблокировать и разблокировать. Необходимо просто проверить, существует ли блокировка смещения, указывающую на текущее Markword в заголовке объекта (в Markword есть бит флага блокировки смещения, чтобы указать, поддерживает ли текущий объект блокировка смещения. Мы можем использовать параметр JVM для установки блокировки смещения).
Что касается выпуска смещенных замков, смещенные блокировки используют механизм освобождения блокировки до тех пор, пока не будет конкуренции, поэтому нить, удерживающая смещенную блокировку
Примечание. В Java6, 7, блокировка смещения запускается по умолчанию
Легкий замок:
Легкая блокировка заключается в том, что перед выполнением блока синхронизации JVM создаст пространство для хранения записи блокировки в кадре стека текущего потока и скопирует в него Markword в заголовке объекта. Затем поток попытается заменить Markword в заголовке Object на указатель на запись блокировки. Если это успешно, текущий поток получает блокировку. Если он сбой, это означает, что другие потоки конкурируют за блокировку, а текущий поток будет вращаться, чтобы получить блокировку.
④ Обновление блокировки:
Если текущий поток не может попробовать приведенный выше метод для получения блокировки, это означает, что текущая блокировка соревнуются, а замок будет обновлен до замок в тяжелом весе.
Разница между легким замком и предвзятым замком:
Легкие замки используют операции CAS для устранения мутекс, используемых в синхронизации без конкуренции, в то время как смещенные замки удаляют всю синхронизацию без конкуренции без конкуренции, и даже операции CAS не выполняются!
⑤ Как реализовать атомные операции в Java:
Прежде чем понять, как Java реализует атомные операции, нам нужно знать, как процессоры реализуют атомные операции:
Процессоры, как правило, делятся на два способа выполнения атомных операций: блокировка кеша и блокировка шины, среди которых блокировка кэша лучше, в то время как блокировка шины является более потребляющим ресурсы. (Мы не будем слишком много объяснять о двух методах блокировки здесь, но в операционной системе будут подробные объяснения)
Java использует (в основном) CAS для реализации атомных операций, но использование CAS для реализации атомных операций также вызовет некоторые из следующих классических проблем:
1) Проблема АБА
Класс AtomicStampedReference предоставлен в JDK для решения (предоставление проверки ожидаемых ссылок и ожидаемых флагов)
2) длительное время цикла и высокие накладные расходы
Не могу решить это, это общая проблема циркуляции
3) Можно гарантировать только атомные операции общей переменной
AtomicReference предоставляется в JDK для решения проблемы, размещая несколько общих переменных в класс для операций CAS.