Ответы:
Краткий ответ: Нет.
Из java.util.concurrent.atomicпакетной документации. Цитировать:
Эффекты памяти для доступа и обновления атомных элементов обычно следуют правилам для летучих компонентов:
getимеет эффекты памяти чтенияvolatileпеременной.setимеет эффект памяти записи (присваивания)volatileпеременной.
Кстати, эта документация очень хорошая, и все объясняется.
AtomicReference::lazySetпредставляет собой более новую (Java 6+) операцию, семантика которой недостижима через volatileпеременные. Смотрите этот пост для получения дополнительной информации.
Есть несколько отличий и компромиссов:
Использование AtomicReferenceget / 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;
Однако второй, скорее всего, будет случайно удален кем-то в будущем во время «очистки кода».