Важный момент о volatile
:
- Синхронизация в Java возможна с использованием ключевых слов Java
synchronized
и volatile
и блокировок.
- В Java у нас не может быть
synchronized
переменной. Использование ключевого слова synchronized
с переменной недопустимо и приведет к ошибке компиляции. Вместо использования переменной synchronized
в Java вы можете использовать переменную java volatile
, которая будет указывать потокам 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
Ключевое слово также используется для передачи содержимого памяти между потоками.
Пример использования без летучих:
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, становятся видимыми для других потоков только после того, как конструктор объекта полностью завершит свое выполнение.
Источник
![enter image description here](https://i.stack.imgur.com/bgHrU.png)
volatile
использование в Java :
Отказоустойчивые итераторы , обычно , реализованы с использованием счетчика volatile
в объекте списка.
- Когда список обновляется, счетчик увеличивается.
- При создании
Iterator
текущее значение счетчика внедряется в объект Iterator
.
- Когда выполняется операция
Iterator
, метод сравнивает два значения счетчика и выдает ConcurrentModificationException
, если они различаются.
Реализация отказоустойчивых итераторов обычно легка. Они обычно полагаются на свойства структур данных конкретной реализации списка. Там нет общей картины.