Что такое атомарная операция
Что проверяют
Понимаете ли вы неделимость с точки зрения других потоков и различаете ли атомарность и видимость.
Как отвечать
Атомарная операция выполняется как единое целое: другой поток не может увидеть её промежуточное состояние. Либо она произошла целиком, либо не произошла вовсе.
Классический пример неатомарности это counter++. Внешне одна строка, внутри три шага: прочитать, увеличить, записать. Два потока могут прочитать одно и то же значение и записать одинаковый результат, потеряв один инкремент.
Что атомарно в Java по спецификации: чтение и запись примитивов до 32 бит и ссылок. Для long и double атомарность не гарантирована, если поле не volatile.
Как добиться атомарности:
- атомарные классы (
AtomicInteger,AtomicLong,AtomicReference): под капотом инструкция сравнения с обменом (CAS). Поток читает значение, вычисляет новое и записывает, только если старое не изменилось, иначе повторяет. Блокировок нет; - synchronized или Lock: делают атомарной целую последовательность операций, а не одну;
- конкурентные коллекции:
computeIfAbsent,merge,putIfAbsentатомарны как одно действие.
Важно развести атомарность и видимость: volatile даёт видимость, но не делает ++ атомарным. synchronized даёт и то, и другое.
Отдельно стоит сказать, что атомарность отдельных операций не даёт атомарности их последовательности: два атомарных вызова подряд это уже не атомарный сценарий.
Где спотыкаются
Считают volatile достаточным для счётчика.
Уверены, что одна строка кода это одна операция.
Делают «проверить и вставить» двумя атомарными вызовами и получают гонку.
Не знают про CAS и не могут объяснить, как атомарность достигается без блокировок.