Gymterview
junior

Для чего используется ключевое слово volatile, synchronized, transient, native?

volatile

Модификатор volatile гарантирует две вещи:

  1. Видимость (visibility) – при записи volatile-переменной значение немедленно сбрасывается в основную память, а при чтении – берётся из основной памяти, а не из кэша потока. Все потоки всегда видят актуальное значение.
  2. Запрет переупорядочивания (ordering) – компилятор и процессор не могут переместить операции чтения/записи volatile-переменной относительно других операций (создаётся memory barrier и устанавливается отношение happens-before).

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

  • Атомарность составных операций. Например, count++ над volatile int count – это три операции (чтение, инкремент, запись), которые НЕ атомарны.

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

  • Переменная-флаг (volatile boolean running = true)
  • Паттерн «одна запись – много чтений»
  • Публикация неизменяемого объекта

synchronized

Ключевое слово synchronized обеспечивает:

  1. Взаимное исключение (mutual exclusion) – только один поток может выполнять синхронизированный блок на одном мониторе одновременно.
  2. Видимость – при входе в synchronized блок поток обновляет свой кэш из основной памяти, при выходе – сбрасывает изменения в основную память.
  3. Атомарность – все операции внутри synchronized блока выполняются как единое целое с точки зрения других потоков.
Пример
// Синхронизированный метод (монитор = this)
public synchronized void method() { /* ... */ }

// Синхронизированный блок (монитор = произвольный объект)
synchronized (lockObject) { /* ... */ }

// Статический синхронизированный метод (монитор = Class<?>)
public static synchronized void staticMethod() { /* ... */ }

transient

Ключевое слово transient к многопоточности отношения не имеет. Оно указывает, что поле класса не должно сериализоваться при использовании стандартной сериализации Java (Serializable).

native

Ключевое слово native к многопоточности также не относится. Оно указывает, что метод реализован в платформозависимом коде (обычно на C/C++) через механизм JNI (Java Native Interface).

Сравнение volatile и synchronized

Характеристика volatile synchronized
Видимость Да Да
Атомарность Только для чтения/записи примитивов и ссылок Да (весь блок)
Взаимное исключение Нет Да
Блокировка потока Нет (неблокирующий) Да (поток может быть заблокирован)
Область применения Только переменные Методы и блоки кода
Производительность Выше Ниже (из-за захвата/освобождения монитора)

Аналогия из жизни. volatile – это табло объявлений в аэропорту: все видят одну и ту же актуальную информацию, но никто не мешает двум сотрудникам одновременно попытаться обновить табло. synchronized – это кабинка с замком: только один человек может войти, и все изменения внутри будут завершены до того, как войдёт следующий.

На собеседовании. Этот вопрос – ловушка: кандидаты иногда начинают подробно рассказывать о transient и native, хотя к многопоточности они не относятся. Покажите, что понимаете разницу, и сосредоточьтесь на volatile и synchronized. Самый частый подвопрос: «Почему volatile не достаточно для count++?» Ответ: потому что инкремент – это три отдельные операции (read-modify-write), и volatile не делает их атомарными.