Важный момент о 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
записи. Смотрите этот ответ и эту ссылку .