Есть ли разница между ссылкой volatile
Object и AtomicReference
в том случае, если я просто использую get()
и set()
-методы из AtomicReference
?
Java volatile reference vs. 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 aVarHandle
. Вы также можете достичь прямойsun.misc.Unsafe
, если вам нравится работать с ножницами.AtomicReference
сам реализуется с помощьюUnsafe
.
Итак, когда хорошо выбрать один из них:
- Нужно только get/set? Stick с изменчивым полем, простейшим решением и наименьшими издержками.
- Вам нужна дополнительная функциональность? Если это производительность (скорость/память), чувствительная часть вашего кода делает выбор между
AtomicReference
/AtomicFieldUpdater
/Unsafe
, где вы склонны платить в читабельности и риске увеличения производительности. Если это не чувствительная область, просто перейдите наAtomicReference
. Авторы библиотек обычно используют сочетание этих методов в зависимости от целевых JDK, ожидаемых ограничений API, ограничений памяти и т.д.