Важный момент о volatile:
- Синхронизация в Java можно с помощью Java ключевых слов
synchronizedи volatileи замки.
- В Java мы не можем иметь
synchronizedпеременную. Использование synchronizedключевого слова с переменной недопустимо и приведет к ошибке компиляции. Вместо использования synchronizedпеременной в Java вы можете использовать volatileпеременную java , которая будет указывать потокам 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 создает экземпляр Singleton и сразу после создания процессор испортит и т. Д., Все остальные потоки не смогут увидеть значение _instanceкак не нулевое, и они будут считать, что ему по-прежнему присваивается значение 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;
}
Код выше не является потокобезопасным. Хотя он проверяет значение экземпляра еще раз в синхронизированном блоке (по соображениям производительности), JIT-компилятор может переставить байт-код таким образом, чтобы ссылка на экземпляр была установлена до того, как конструктор завершит свое выполнение. Это означает, что метод getInstance () возвращает объект, который, возможно, не был полностью инициализирован. Чтобы сделать код потокобезопасным, ключевое слово volatile может использоваться начиная с Java 5 для переменной экземпляра. Переменные, помеченные как volatile, становятся видимыми для других потоков только после того, как конструктор объекта полностью завершит свое выполнение.
Источник

volatileиспользование в Java :
Отказоустойчивые итераторы обычно реализуются с использованием volatileсчетчика объекта списка.
- Когда список обновляется, счетчик увеличивается.
- Когда
Iteratorсоздается, текущее значение счетчика внедряется в Iteratorобъект.
- Когда
Iteratorоперация выполняется, метод сравнивает два значения счетчика и выдает a, ConcurrentModificationExceptionесли они различны.
Реализация отказоустойчивых итераторов обычно легка. Они обычно полагаются на свойства структур данных конкретной реализации списка. Там нет общей картины.
volatileкоторое появилось в новой модели памяти Java, определенной в JSR 133: когда поток читаетvolatileпеременную, он видит не только значение, записанное в него последним другим потоком, но также все другие записи в другие переменные, которые были видны в этом другом потоке во времяvolatileзаписи. Смотрите этот ответ и эту ссылку .