Изменчивая ссылка Java против AtomicReference

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

Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
140
0
40 188
6
Перейти к ответу Данный вопрос помечен как решенный

Ответы 6

Ответ принят как подходящий

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

Из документации пакета java.util.concurrent.atomic. Цитировать:

The memory effects for accesses and updates of atomics generally follow the rules for volatiles:

  • get has the memory effects of reading a volatile variable.
  • set has the memory effects of writing (assigning) a volatile variable.

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


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

И более длинный ответ был бы?

Julien Grenier 12.11.2008 08:01

Согласовано. Нам хоть ссылка нужна.

Julien Chastang 30.01.2009 19:57

Ссылка на более длинный ответ: java.sun.com/j2se/1.5.0/docs/api/java/util/concurrent/atomic‌ /…

Alex Siman 03.11.2009 02:40

Нет, нет.

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

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

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

Таким образом, разница заключается в их производительности. Если бы не было разницы, вы бы никогда не предложили использовать одно вместо другого.

B T 07.02.2012 01:07

Производительность почти такая же. AtomicRefrence увеличивает сложность и использование памяти.

Peter Lawrey 07.02.2012 01:09

@BT Поле volatile может использоваться как любое обычное поле, тогда как для доступа к значению в AtomicReference требуется прохождение методов get и set.

David Harkness 03.09.2014 21:25

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

private volatile V value;

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

«Исходный код JDK - один из лучших способов разрешить подобные недоразумения» => Я не обязательно согласен - javadoc (который является контрактом класса) - лучший способ. То, что вы найдете в коде, отвечает на вопрос для конкретной реализации, но код может измениться.
assylias 03.02.2013 20:59

Например, эта переменная в hashmap был изменчивым в JDK 6, но больше не изменчивым в Java 7. Если бы вы основывали свой код на том факте, что переменная была изменчивой, она бы сломалась при обновлении вашего JDK ... По общему признанию, пример другой но вы поняли суть.

assylias 03.02.2013 21:00

Это стандартная аббревиатура CAS?

abbas 09.08.2019 13:32

Сравнить и поменять местами =)

endless 15.08.2019 20:03

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

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

  2. объем памяти увеличивается (при условии сжатой среды ООП, что верно для большинства виртуальных машин):

    • изменчивый ref = 4b
    • AtomicReference = 4b + 16b (заголовок объекта 12b + поле ссылки 4b)
  3. 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;

Однако второй, скорее всего, будет случайно удален кем-то в будущем во время «чистки кода».

Другие вопросы по теме