← Назад к вопросам

Будет ли атомарная операция с volatile переменной?

2.4 Senior🔥 191 комментариев
#JVM и управление памятью#Многопоточность

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

# Будет ли атомарная операция с volatile переменной?

Краткий ответ

Нет, volatile не гарантирует атомарность операций. volatile обеспечивает только видимость изменений между потоками, но не обеспечивает атомарность составных операций.

Что такое volatile?

volatile — это модификатор в Java, который:

public class VolatileExample {
    private volatile int counter = 0;  // видно всем потокам
}

Гарантии volatile:

  • ✅ Видимость (visibility) — изменения видны всем потокам
  • ✅ Запрет на переупорядочивание (memory barriers)
  • ❌ Не защищает от race conditions
  • ❌ Не атомарна

Почему volatile не атомарен?

Атомарность — это неделимость операции, выполняемой как одна единица. Рассмотрим пример:

public class NonAtomicVolatile {
    private volatile long value = 0;
    
    // Составная операция (не атомарна!)
    public void increment() {
        value++;  // 3 операции: read -> add -> write
    }
    
    public long getValue() {
        return value;
    }
}

Что происходит при value++ с двумя потоками:

Поток 1: read (0) -> add -> write (1)
Поток 2:          read (0) -> add -> write (1)

Результат: 1 вместо 2 (race condition)

Dаже с volatile, оба потока читают 0, увеличивают до 1 и записывают 1. Одно значение потеряно.

Как обеспечить атомарность?

Вариант 1: synchronized

public class AtomicWithSync {
    private volatile long value = 0;
    
    public synchronized void increment() {
        value++;  // Теперь атомарна
    }
    
    public synchronized long getValue() {
        return value;
    }
}

Вариант 2: AtomicLong (рекомендуется)

public class AtomicExample {
    private AtomicLong counter = new AtomicLong(0);
    
    public void increment() {
        counter.incrementAndGet();  // Атомарна, без блокировок
    }
    
    public long getValue() {
        return counter.get();
    }
}

Преимущества AtomicLong:

  • ✅ Атомарные операции
  • ✅ Без явных блокировок (lock-free)
  • ✅ Выше производительность чем synchronized
  • ✅ CAS (Compare-And-Swap) операции

Когда volatile достаточно?

volatile подходит для простых операций чтения/записи:

public class FlagExample {
    private volatile boolean shutdown = false;
    
    public void stop() {
        shutdown = true;  // Атомарная операция сама по себе
    }
    
    public void run() {
        while (!shutdown) {  // Видит актуальное значение
            doWork();
        }
    }
}

Здесь volatile достаточна, потому что запись булева значения — это атомарная операция на аппаратном уровне.

Таблица сравнения

ХарактеристикаvolatilesynchronizedAtomicLong
Видимость
Атомарность простой записи
Атомарность составных операций
ПроизводительностьВысокаяНизкаяОчень высокая
Lock-free

Выводы

  1. volatile ≠ атомарно — это разные концепции
  2. volatile гарантирует видимость, но не защищает от race conditions
  3. Для составных операций используй synchronized, AtomicXxx или ReentrantLock
  4. AtomicLong/AtomicInteger — лучший выбор для счётчиков в многопоточной среде
  5. Всегда думай о том, какие операции являются атомарными на аппаратном уровне
Будет ли атомарная операция с volatile переменной? | PrepBro