Обеспечивает ли ключевое слово volatile в Java атомарность операций?

«Обеспечивает ли ключевое слово volatile в Java атомарность операций?» — вопрос из категории Java Core, который задают на 10% собеседований Java Разработчик. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

Нет, volatile не обеспечивает атомарность операций.

Что гарантирует volatile:

  1. Видимость изменений: Гарантирует, что все потоки увидят самое актуальное значение переменной. Запись в volatile-переменную происходит в основную память, минуя кэши процессоров.
  2. Запрет переупорядочивания: Компилятор и процессор не могут переупорядочить операции с volatile-переменной относительно других операций чтения/записи.

Почему операции не атомарны? Сложные операции, такие как инкремент (i++), состоят из нескольких шагов (чтение, изменение, запись). Поток может быть прерван между этими шагами, что приводит к "потере" обновлений.

Пример проблемы:

volatile int counter = 0;
// Операция НЕ атомарна
counter++; // Эквивалентно: int temp = counter; temp = temp + 1; counter = temp;

Атомарные альтернативы:

  • Классы из java.util.concurrent.atomic:
    AtomicInteger atomicCounter = new AtomicInteger(0);
    atomicCounter.incrementAndGet(); // Атомарная операция
  • Синхронизация:

    private final Object lock = new Object();
    private int counter = 0;
    
    public void increment() {
        synchronized(lock) {
            counter++;
        }
    }