предисловие
Чтобы изучить многопоточность Java, вы должны быть знакомы с механизмом ключевого слова volatile. В последнее время блогеры прочитали много тематических блогов о volatile, и имеют немного предварительного понимания и понимания о них.Ниже приводится их описание своими словами.
Какая польза?
volatile в основном предоставляет две функции для измененной переменной
- видимость
- Предотвратить изменение порядка инструкций
В этом блоге в основном обсуждается изменчивая видимость, и в будущем будет опубликована запись в блоге о переупорядочении инструкций.
Что такое видимость?
Одна картинка стоит тысячи слов
- У каждого потока своя рабочая память (можно понять, что у каждого повара свой вок)
- Все потоки имеют одну основную память (все повара в ресторане используют один и тот же холодильник)
- Прежде чем каждый поток будет обрабатывать данные, он отправится в основную память для получения данных (шеф-повар должен подойти к холодильнику, чтобы получить ингредиенты перед приготовлением).
- Тема: Шеф-повар
- Рабочая память: железный горшок
- store&load: положить приготовленную еду, взять ингредиенты
- Основная память: холодильник
Читатели могут рассмотреть следующие сценарии:
В ресторан пришел клиент и заказал тушеную свинину.В это время там было два повара (при условии, что повара не общались друг с другом).Поскольку они не общались друг с другом, то оба повара открыли холодильник и достали ингредиенты для начала приготовления.
В итоге было зажарено две порции тушеной свинины, а клиентам нужна была только одна. Почему это получается?
Так как нет видимости между поварами.
Помещение этого сценария в JAVA:
Поток A взял переменную из основной памяти в рабочую память и не поместил ее обратно в основную память вовремя после операции, поэтому поток B отправился на выборку переменной.ИстекшийТеперь берется переменная перед операцией потока A.
Как добиться видимости?
Давайте сначала представим атомарные операции между рабочей памятью 8 и основной памятью, определенные в модели памяти Java.
- замок (замок): действует напеременные в основной памяти, который идентифицирует переменную как исключительное для потока состояние.
- разблокировать (разблокировать): действует наосновная памятьЗаблокированная переменная освобождается, и освобожденная переменная может быть заблокирована другими потоками.
- читать (читать): действует наосновная памятьПеременная, которая передает значение переменной из основной памяти в рабочую память потока для использования последующими действиями загрузки.
- load (загрузить): воздействуя на переменную *** рабочей памяти ***, помещает значение переменной, полученное операцией чтения из основной памяти, в копию переменной рабочей памяти.
- use (использование): воздействует на переменную в рабочей памяти, которая передает значение переменной в рабочей памяти механизму выполнения всякий раз, когда виртуальная машина встречает байт-код, которому необходимо использовать значение переменной. Эта операция будет выполняться, когда команда выполняется.
- assign (назначение): воздействует на переменную в рабочей памяти, присваивает значение, полученное от механизма выполнения, переменной в рабочей памяти, всякий раз, когда виртуальная машина встречает инструкцию байт-кода, которая присваивает значение переменной, выполняет эту операцию.
- store (хранение): переменная, действующая на *** рабочую память ***, которая передает значение переменной из рабочей памяти в основную память для последующих операций записи для использования
- писать (писать): действует наосновная памятьпеременная, которая помещает значение, полученное операцией сохранения из рабочей памяти, в переменную в основной памяти.
Случай чтения и присвоения обычной переменной
- В чем вред?
Предположим, есть
int a=0;
Поток 1 и поток 2 выполняются один раз соответственно, и в идеале конечное значение a равно 2.
a++;
После того, как поток 1 выполнит операцию присваивания, реальное значение переменной а изменилось с 0 на 1, но этот процесс происходит в рабочей памяти и невидим для других потоков. значение по-прежнему равно 0, потому что нет видимости, а операция потока 2 просто повторяет операцию потока 1, снова делая изменение с 0 на 1.Ожидаемое значение a=2 не достигается.
Случай чтения и присвоения volatile переменной
- Невозможно прочитать и загрузить перед использованием
- assign должен сопровождаться store&write
то естьread-load-useиassign-store-writeстановится двумя неразделимыми атомарными операциями
Хотя в это время между использованием и назначением все еще существует вакуумный период, возможно, что переменная будет прочитана другими потоками, но значение переменной в основной памяти и переменной в любой рабочей памяти равны в любой точке. во время. Эта функция делает volatile-переменные непригодными для участия в операциях, зависящих от текущего значения, таких как автоинкремент. Так где же можно использовать volatile в зависимости от характеристик видимости? Виртуальная машина Java упоминает:
Результат операции не зависит от текущего значения переменной (то есть результат не зависит от генерации промежуточных результатов) или может гарантировать, что только один поток изменяет значение переменной
Обычно летучие используются какспасти состояниеЛогическое значение .
Частично упоминается из