Java volatile reference vs. AtomicReference

Есть ли разница между ссылкой volatile Object и AtomicReference в том случае, если я просто использую get() и set() -методы из AtomicReference?

Ответ 1

Короткий ответ: Нет.

Из java.util.concurrent.atomic doc:

Эффекты памяти для доступа и обновлений атоматики обычно следуют правилам для летучих:

  • get имеет эффект памяти при чтении переменной volatile.
  • set имеет эффекты памяти записи (назначения) переменной volatile.

Кстати, документ для пакета очень хорош, и все объясняется...


lazySet (введенный в Java 6) представляет собой более новую введенную операцию, которая имеет семантику, недостижимую с помощью переменных volatile; см. этот пост для получения дополнительной информации.

Ответ 2

Нет, нет.

Дополнительной мощностью, предоставляемой AtomicReference, является метод compareAndSet() и друзей. Если вам не нужны эти методы, волатильная ссылка предоставляет ту же семантику, что и AtomicReference.set() и .get().

Ответ 3

Исходный код JDK - один из лучших способов ответа на подобные недоразумения. Если вы посмотрите на код в AtomicReference, он использует переменную volatie для хранения объектов.

private volatile V value;

Итак, очевидно, что если вы просто используете get() и set() на AtomicReference, это похоже на использование изменчивой переменной. Но, как отмечали другие читатели, AtomicReference предоставляет дополнительную семантику CAS. Итак, сначала решите, хотите ли вы семантику CAS или нет, и если вы только тогда используете AtomicReference.

Ответ 4

AtomicReference предоставляет дополнительную функциональность, которую не дает простая изменчивая переменная. Поскольку вы прочитали API, вы это узнаете, но также предоставляет блокировку, которая может быть полезна для некоторых операций.

Однако, если вам не нужна эта дополнительная функциональность, я предлагаю вам использовать простое поле volatile.

Ответ 5

Существует несколько отличий и компромиссов:

  • Использование AtomicReference get/set имеет ту же JMM-семантику как изменчивое поле (как состояния javadoc), но AtomicReference является оберткой вокруг ссылки, поэтому любой доступ к полю включает в себя дальнейшую последовательность указателей.

  • Знак памяти умножается (при условии, что сжатая среда OOPs, которая верна для большинства виртуальных машин):

    • volatile ref = 4b
    • AtomicReference= 4b + 16b (заголовок объекта 12b + поле 4b ref)
  • AtomicReference предлагает более богатый API, чем волатильная ссылка. Вы можете восстановить API для volatile reference, используя AtomicFieldUpdater, или с Java 9 a VarHandle. Вы также можете достичь прямой sun.misc.Unsafe, если вам нравится работать с ножницами. AtomicReference сам реализуется с помощью Unsafe.

Итак, когда хорошо выбрать один из них:

  • Нужно только get/set? Stick с изменчивым полем, простейшим решением и наименьшими издержками.
  • Вам нужна дополнительная функциональность? Если это производительность (скорость/память), чувствительная часть вашего кода делает выбор между AtomicReference/AtomicFieldUpdater/Unsafe, где вы склонны платить в читабельности и риске увеличения производительности. Если это не чувствительная область, просто перейдите на AtomicReference. Авторы библиотек обычно используют сочетание этих методов в зависимости от целевых JDK, ожидаемых ограничений API, ограничений памяти и т.д.