Ключевое слово volatile
Ключевое слово volatile применяется к полям класса
и сообщает виртуальной машине Java, что значение этой
переменной может изменяться другими потоками. При чтении
такой переменной поток всегда получает актуальное значение
из основной памяти, а при записи - немедленно сбрасывает
его в основную память, минуя кэш процессора. Это решает
проблему видимости, но не обеспечивает атомарности
составных операций.
Синтаксис
volatile тип имяПеременной;
Пример
Объявим volatile-поле и запустим поток, который устанавливает флаг остановки, а главный поток ожидает его изменения:
public class Main
{
static volatile boolean flag = false;
public static void main(String[] args) throws InterruptedException
{
Thread worker = new Thread(() -> {
try
{
Thread.sleep(100);
}
catch (InterruptedException e)
{
Thread.currentThread().interrupt();
}
flag = true;
System.out.println("Flag set to true");
});
worker.start();
while (!flag)
{
}
System.out.println("Main thread sees flag = " + flag);
worker.join();
}
}
Результат выполнения кода:
"Flag set to true"
"Main thread sees flag = true"
Пример
Продемонстрируем, что volatile не делает
операцию i++ атомарной. Запустим два потока,
каждый из которых увеличивает счётчик много раз:
public class Main
{
static volatile int counter = 0;
public static void main(String[] args) throws InterruptedException
{
Runnable task = () -> {
for (int i = 0; i < 10000; i++)
{
counter++;
}
};
Thread t1 = new Thread(task);
Thread t2 = new Thread(task);
t1.start();
t2.start();
t1.join();
t2.join();
System.out.println("counter = " + counter);
}
}
Ожидаемый результат может отличаться от 20000
из-за гонки данных. Возможный вывод:
"counter = 18743"
Смотрите также
-
ключевое слово
synchronized,
которое обеспечивает атомарность и видимость -
ключевое слово
final,
которое запрещает изменение переменной -
ключевое слово
static,
которое делает поле общим для всех экземпляров -
ключевое слово
transient,
которое исключает поле из сериализации