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




Короткий ответ: нет.
Из документации пакета java.util.concurrent.atomic. Цитировать:
The memory effects for accesses and updates of atomics generally follow the rules for volatiles:
gethas the memory effects of reading avolatilevariable.sethas the memory effects of writing (assigning) avolatilevariable.
Кстати, документация очень хорошая, и все объяснено.
AtomicReference::lazySet - это более новая (Java 6+) операция, которая имеет семантику, недостижимую с помощью переменных volatile. См. эта почта для получения дополнительной информации.
Согласовано. Нам хоть ссылка нужна.
Ссылка на более длинный ответ: java.sun.com/j2se/1.5.0/docs/api/java/util/concurrent/atomic /…
Нет, нет.
Дополнительные возможности, предоставляемые AtomicReference, - это метод compareAndSet () и его друзья. Если вам не нужны эти методы, изменчивая ссылка обеспечивает ту же семантику, что и AtomicReference.set () и .get ().
AtomicReference обеспечивает дополнительную функциональность, которую не предоставляет простая изменчивая переменная. Поскольку вы прочитали API Javadoc, вы это знаете, но он также обеспечивает блокировку, которая может быть полезна для некоторых операций.
Однако, если вам не нужна эта дополнительная функция, я предлагаю вам использовать простое поле volatile.
Таким образом, разница заключается в их производительности. Если бы не было разницы, вы бы никогда не предложили использовать одно вместо другого.
Производительность почти такая же. AtomicRefrence увеличивает сложность и использование памяти.
@BT Поле volatile может использоваться как любое обычное поле, тогда как для доступа к значению в AtomicReference требуется прохождение методов get и set.
Исходный код JDK - один из лучших способов справиться с подобной путаницей. Если вы посмотрите на код в AtomicReference, он использует переменную volatie для хранения объектов.
private volatile V value;
Итак, очевидно, что если вы собираетесь просто использовать get () и set () в AtomicReference, это похоже на использование изменчивой переменной. Но, как отмечали другие читатели, AtomicReference предоставляет дополнительную семантику CAS. Итак, сначала решите, нужна ли вам семантика CAS или нет, и только тогда используйте AtomicReference.
Например, эта переменная в hashmap был изменчивым в JDK 6, но больше не изменчивым в Java 7. Если бы вы основывали свой код на том факте, что переменная была изменчивой, она бы сломалась при обновлении вашего JDK ... По общему признанию, пример другой но вы поняли суть.
Это стандартная аббревиатура CAS?
Сравнить и поменять местами =)
Есть несколько отличий и компромиссов:
Использование AtomicReference get / set имеет тот же Семантика JMM, что и изменчивое поле (как указано в javadoc), но AtomicReference является оболочкой вокруг ссылки, поэтому любой доступ к полю включает дальнейшую погоню за указателем.
объем памяти увеличивается (при условии сжатой среды ООП, что верно для большинства виртуальных машин):
AtomicReference = 4b + 16b (заголовок объекта 12b + поле ссылки 4b)AtomicReference предлагает более богатый API, чем изменчивый справочник. Вы можете восстановить API для изменчивой ссылки с помощью AtomicFieldUpdater или с помощью Java 9 VarHandle. Вы также можете добраться прямо до sun.misc.Unsafe, если вам нравится бегать с ножницами. Сам AtomicReference реализован с использованием Unsafe.
Итак, когда лучше выбрать одно из них:
AtomicReference / AtomicFieldUpdater / Unsafe, где вы, как правило, платите удобочитаемостью и рискуете увеличением производительности. Если это не чувствительная область, просто выберите AtomicReference. Разработчики библиотек обычно используют сочетание этих методов в зависимости от целевых JDK, ожидаемых ограничений API, ограничений памяти и так далее.Иногда, даже если вы используете только методы получения и набора, AtomicReference может быть хорошим выбором:
Пример с изменчивым:
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;
Однако второй, скорее всего, будет случайно удален кем-то в будущем во время «чистки кода».
И более длинный ответ был бы?