Вопрос-ответ

What is the volatile keyword useful for?

Для чего полезно ключевое слово 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:


  1. Синхронизация в Java возможна с помощью ключевых слов Java synchronized и volatile и блокировок.

  2. В Java у нас не может быть synchronized переменной. Использование synchronized ключевого слова с переменной незаконно и приведет к ошибке компиляции. Вместо использования synchronized переменной в Java вы можете использовать переменную java volatile, которая даст указание потокам JVM считывать значение volatile переменной из основной памяти и не кэшировать ее локально.

  3. Если переменная не является общей для нескольких потоков, то нет необходимости использовать 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 операции метод сравнивает два значения счетчика и выдает a ConcurrentModificationException, если они отличаются.

Реализация отказоустойчивых итераторов обычно невелика. Обычно они полагаются на свойства структур данных конкретной реализации 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 поток, выполняющий цикл, может никогда не увидеть изменения на закрытие.

Обратите внимание, что синхронизация не требуется

java multithreading