В Java, являются ли атомарные переменные (Atomic*) эквивалентом volatile примитивов?

«В Java, являются ли атомарные переменные (Atomic*) эквивалентом volatile примитивов?» — вопрос из категории Java Core, который задают на 10% собеседований Java Разработчик. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

Нет, атомарные переменные (например, AtomicInteger) не являются эквивалентом volatile примитивов. Они решают разные задачи, хотя оба связаны с многопоточностью.

Ключевые различия:

Аспект volatile переменная Atomic класс (например, AtomicInteger)
Гарантия Видимость изменений между потоками (happens-before). Атомарность составных операций (например, инкремента) + видимость.
Операции Чтение и запись одиночного значения. Атомарные методы: incrementAndGet(), compareAndSet(), getAndUpdate().
Производительность Выше для простых операций чтения/записи. Ниже из-за дополнительной логики (часто на основе CAS).

Практический пример:

volatile int volatileCounter = 0;
AtomicInteger atomicCounter = new AtomicInteger(0);

// Потокобезопасный инкремент с AtomicInteger
atomicCounter.incrementAndGet(); // Атомарная операция "чтение-изменение-запись"

// НЕ потокобезопасный инкремент, даже с volatile
volatileCounter++; // Состоит из трёх шагов: чтение, инкремент, запись. Нет атомарности.

Когда что использовать:

  • volatile — для простых флагов или переменных состояния, где важна только мгновенная видимость последней записи.
  • Atomic-классы — для счетчиков, аккумуляторов или любых операций, где значение зависит от предыдущего (инкремент, сравнение с обменом).