Ответы:
Краткий ответ: Нет.
Из java.util.concurrent.atomic
пакетной документации. Цитировать:
Эффекты памяти для доступа и обновления атомных элементов обычно следуют правилам для летучих компонентов:
get
имеет эффекты памяти чтенияvolatile
переменной.set
имеет эффект памяти записи (присваивания)volatile
переменной.
Кстати, эта документация очень хорошая, и все объясняется.
AtomicReference::lazySet
представляет собой более новую (Java 6+) операцию, семантика которой недостижима через volatile
переменные. Смотрите этот пост для получения дополнительной информации.
Есть несколько отличий и компромиссов:
Использование AtomicReference
get / set имеет ту же семантику JMM, что и энергозависимое поле (как состояния javadoc), но AtomicReference
является оберткой вокруг ссылки, поэтому любой доступ к полю включает дальнейшую погоню за указателем .
Объем памяти увеличивается (при условии сжатой среды ООП, что справедливо для большинства виртуальных машин):
AtomicReference
= 4b + 16b (заголовок объекта 12b + поле ссылки 4b)AtomicReference
предлагает более богатый API, чем нестабильная ссылка. Вы можете восстановить API для энергозависимой ссылки с помощью AtomicFieldUpdater
или с помощью Java 9 a VarHandle
. Вы также можете связаться прямо, sun.misc.Unsafe
если вам нравится бегать с ножницами. AtomicReference
Сам реализован с помощью Unsafe
.
Итак, когда это хорошо, чтобы выбрать один над другим:
AtomicReference
/ AtomicFieldUpdater
/, Unsafe
где вы склонны платить за удобочитаемость и риск увеличения производительности. Если это не чувствительная область просто пойти AtomicReference
. Авторы библиотек обычно используют сочетание этих методов в зависимости от целевых JDK, ожидаемых ограничений API, ограничений памяти и так далее.Исходный код JDK - один из лучших способов решить такую проблему. Если вы посмотрите на код в AtomicReference, он использует переменную volatie для хранения объектов.
private volatile V value;
Итак, очевидно, что если вы собираетесь просто использовать get () и set () в AtomicReference, это похоже на использование переменной volatile. Но, как отметили другие читатели, AtomicReference предоставляет дополнительную семантику CAS. Итак, сначала решите, хотите ли вы семантику CAS или нет, и если вы делаете только тогда, используйте AtomicReference.
AtomicReference
обеспечивает дополнительную функциональность, которую не обеспечивает обычная переменная переменная. Когда вы прочитали API Javadoc, вы это узнаете, но он также предоставляет блокировку, которая может быть полезна для некоторых операций.
Однако, если вам не нужны эти дополнительные функции, я предлагаю вам использовать простое volatile
поле.
volatile
Поле можно использовать как любое обычное поле, тогда как для доступа к значению AtomicReference
требуется пройти через методы get
и set
методы.
Иногда, даже если вы используете только get и set, AtomicReference может быть хорошим выбором:
Пример с volatile:
private volatile Status status;
...
public setNewStatus(Status newStatus){
status = newStatus;
}
public void doSomethingConditionally() {
if(status.isOk()){
System.out.println("Status is ok: " + status); // here status might not be OK anymore because in the meantime some called setNewStatus(). setNewStatus should be synchronized
}
}
Реализация с AtomicReference обеспечит вам бесплатную синхронизацию копирования при записи.
private AtomicReference<Status> statusWrapper;
...
public void doSomethingConditionally() {
Status status = statusWrapper.get();
if(status.isOk()){
System.out.println("Status is ok: " + status); // here even if in the meantime some called setNewStatus() we're still referring to the old one
}
}
Можно сказать, что у вас все еще может быть правильная копия, если вы замените:
Status status = statusWrapper.get();
с участием:
Status statusCopy = status;
Однако второй, скорее всего, будет случайно удален кем-то в будущем во время «очистки кода».