Для чего полезно ключевое слово volatile?
Сегодня на работе я наткнулся на volatile
ключевое слово в Java. Не будучи очень знакомым с ним, я нашел это объяснение.
Учитывая подробности, в которых в этой статье объясняется рассматриваемое ключевое слово, вы когда-нибудь использовали его или могли ли вы когда-нибудь видеть случай, когда вы могли бы использовать это ключевое слово правильным образом?
Переведено автоматически
Ответ 1
volatile
имеет семантику для видимости памяти. По сути, значение volatile
поля становится видимым для всех читателей (в частности, для других потоков) после завершения операции записи в нем. Без volatile
читатели могли видеть некоторые не обновленные значения.
Отвечая на ваш вопрос: Да, я использую volatile
переменную, чтобы контролировать, продолжает ли некоторый код цикл. Цикл проверяет volatile
значение и продолжается, если оно есть true
. Условие может быть установлено равным false
путем вызова метода "stop". Цикл видит false
и завершается, когда проверяет значение после завершения выполнения метода stop.
В книге "Параллелизм Java на практике", которую я настоятельно рекомендую, дается хорошее объяснение volatile
. Эта книга написана тем же человеком, который написал статью об IBM, на которую ссылается вопрос (фактически, он цитирует свою книгу в конце этой статьи). Я использую volatile
то, что в его статье называется "флаг состояния шаблона 1".
Если вы хотите узнать больше о том, как volatile
работает под капотом, прочитайте о модели памяти Java. Если вы хотите выйти за рамки этого уровня, ознакомьтесь с хорошей книгой по компьютерной архитектуре, такой как Hennessy & Patterson, и прочитайте о согласованности кэша.
Ответ 2
“... модификатор volatile гарантирует, что любой поток, считывающий поле, увидит самое последнее записанное значение”. - Джош Блох
Если вы думаете об использовании volatile
, прочитайте о пакете, java.util.concurrent
который описывает атомарное поведение.
Запись в Википедии о одноэлементном шаблоне показывает, что volatile используется.
Ответ 3
Volatile(vɒlətʌɪl): легко испаряется при нормальных температурах
Важный момент о volatile
:
- Синхронизация в Java возможна с помощью ключевых слов Java
synchronized
иvolatile
и блокировок. - В Java у нас не может быть
synchronized
переменной. Использованиеsynchronized
ключевого слова с переменной незаконно и приведет к ошибке компиляции. Вместо использованияsynchronized
переменной в Java вы можете использовать переменную javavolatile
, которая даст указание потокам JVM считывать значениеvolatile
переменной из основной памяти и не кэшировать ее локально. - Если переменная не является общей для нескольких потоков, то нет необходимости использовать
volatile
ключевое слово.
Пример использования volatile
:
public class Singleton {
private static volatile Singleton _instance; // volatile variable
public static Singleton getInstance() {
if (_instance == null) {
synchronized (Singleton.class) {
if (_instance == null)
_instance = new Singleton();
}
}
return _instance;
}
}
Мы лениво создаем экземпляр в момент поступления первого запроса.
Если мы не создадим _instance
переменную volatile
, то поток, создающий экземпляр Singleton
, не сможет взаимодействовать с другим потоком. Итак, если поток A создает одноэлементный экземпляр и сразу после создания происходит сбой процессора и т.д., все остальные потоки не смогут увидеть значение _instance
как not null и они будут полагать, что ему по-прежнему присвоено значение null.
Почему это происходит? Поскольку потоки чтения не выполняют никакой блокировки, и пока поток записи не выйдет из синхронизированного блока, память не будет синхронизирована и значение _instance
не будет обновлено в основной памяти. С ключевым словом Volatile в Java это обрабатывается самой Java, и такие обновления будут видны всем потокам чтения.
Вывод:
volatile
ключевое слово также используется для передачи содержимого памяти между потоками.
Пример использования без volatile:
public class Singleton {
private static Singleton _instance; //without volatile variable
public static Singleton getInstance() {
if (_instance == null) {
synchronized(Singleton.class) {
if (_instance == null)
_instance = new Singleton();
}
}
return _instance;
}
}
Приведенный выше код не является потокобезопасным. Хотя он еще раз проверяет значение instance в синхронизированном блоке (по соображениям производительности), JIT-компилятор может изменить байт-код таким образом, что ссылка на экземпляр будет установлена до того, как конструктор завершит свое выполнение. Это означает, что метод getInstance() возвращает объект, который, возможно, был инициализирован не полностью. Чтобы сделать код потокобезопасным, ключевое слово volatile может использоваться начиная с Java 5 для переменной экземпляра. Переменные, помеченные как volatile, становятся видимыми другим потокам только после того, как конструктор объекта полностью завершит свое выполнение.
Источник
volatile
использование в Java:
Отказоустойчивые итераторы обычно реализуются с использованием volatile
счетчика в объекте list.
- Когда список обновляется, счетчик увеличивается.
- Когда
Iterator
создается, текущее значение счетчика внедряется вIterator
объект. - При выполнении
Iterator
операции метод сравнивает два значения счетчика и выдает aConcurrentModificationException
, если они отличаются.
Реализация отказоустойчивых итераторов обычно невелика. Обычно они полагаются на свойства структур данных конкретной реализации list . Общего шаблона нет.
Ответ 4
volatile
очень полезно для остановки потоков.
Не то чтобы вы должны писать свои собственные потоки, в Java 1.6 есть много хороших пулов потоков. Но если вы уверены, что вам нужен поток, вам нужно знать, как его остановить.
Шаблон, который я использую для потоков, является:
public class Foo extends Thread {
private volatile boolean close = false;
public void run() {
while(!close) {
// do work
}
}
public void close() {
close = true;
// interrupt here if needed
}
}
В приведенном выше сегменте кода поток, считывающий close
в цикле while, отличается от того, который вызывает close()
. Без volatile поток, выполняющий цикл, может никогда не увидеть изменения на закрытие.
Обратите внимание, что синхронизация не требуется