Нестабільна посилання Java проти AtomicReference


135

Чи є різниця між volatileпосиланням на об’єкт і AtomicReferenceу випадку, якщо я просто використовую get()і set()-методи від AtomicReference?

Відповіді:


114

Коротка відповідь: Ні.

З java.util.concurrent.atomicпакетної документації. Цитувати:

Ефекти пам’яті для доступу та оновлень атома зазвичай відповідають правилам летючих речовин:

  • getмає ефекти на пам'ять читання volatileзмінної.
  • setмає ефекти на пам'ять написання (призначення) volatileзмінної.

До речі, ця документація дуже гарна і все пояснено.


AtomicReference::lazySetце новіша операція (Java 6+), що має семантику, недоступну за допомогою volatileзмінних. Дивіться цю публікацію для отримання додаткової інформації.


11
І довша відповідь була б?
Жульєн Греньє

Домовились. Нам хоча б потрібне посилання.
Жульєн Частанг

2
Посилання на довшу відповідь: java.sun.com/j2se/1.5.0/docs/api/java/util/concurrent/atomic/…
Алекс Сіман

42

Ні, немає.

Додаткову потужність, яку надає AtomicReference, - це метод CompareAndSet () та друзів. Якщо ці методи вам не потрібні, мінлива посилання надає ту саму семантику, як AtomicReference.set () та .get ().


14

Існує кілька відмінностей і компромісів:

  1. Використання AtomicReferenceget / set має ту саму семантику JMM , що і мінливе поле (як заявляє javadoc), але AtomicReferenceє обгорткою навколо посилання, тому будь-який доступ до поля передбачає подальше погоню за покажчиком .

  2. Шлях пам’яті множиться (припускаючи стиснене середовище OOPs, що справедливо для більшості віртуальних машин):

    • летюча реф = 4b
    • AtomicReference = 4b + 16b (12b заголовок об’єкта + 4b ref поле)
  3. AtomicReferenceпропонує більш багатий API, ніж мінливий посилання. Ви можете відновити API для енергонезалежних посилань, використовуючи AtomicFieldUpdaterабо за допомогою Java 9 a VarHandle. Ви також можете досягти прямо, sun.misc.Unsafeякщо вам подобається бігати ножицями. AtomicReferenceсама реалізується за допомогою Unsafe.

Отже, коли добре вибирати одне над іншим:

  • Тільки потрібно отримати / встановити? Дотримуйтесь мінливого поля, найпростішого рішення та найнижчих надвір.
  • Потрібна додаткова функціональність? Якщо це чутлива до швидкості / надмірної пам'яті частина вашого коду, зробіть вибір між AtomicReference/ AtomicFieldUpdater/ Unsafeде ви, як правило, платите за читабельність та ризик для підвищення продуктивності. Якщо це не чутлива область, просто зайдіть AtomicReference. Письменники бібліотеки зазвичай використовують поєднання цих методів залежно від націлених JDK, очікуваних обмежень API, обмежень пам'яті тощо.

7

Вихідний код JDK - це один з найкращих способів відповіді на подібні плутанини. Якщо ви подивитеся на код у AtomicReference, він використовує змінну volatie для зберігання об'єктів.

private volatile V value;

Отже, очевидно, якщо ви збираєтеся просто використовувати get () і set () на AtomicReference, це як використання летючої змінної. Але, як коментують інші читачі, AtomicReference надає додаткову семантику CAS. Отже, спочатку вирішіть, хочете ви семантику CAS чи ні, а якщо ви робите лише тоді, використовуйте AtomicReference.


13
"JDK вихідний код - це один з найкращих способів відповіді на подібні плутанини" => Я не обов'язково згоден - javadoc (що є контрактом класу) - найкращий спосіб. Що ви знайдете в коді, відповідає на питання щодо конкретної реалізації, але код може змінитися.
assylias

4
Наприклад, ця змінна хешмап була мінливою в JDK 6, але вже не є мінливою в Java 7. Чи ви базували свій код на тому, що змінна була мінливою, вона зламалася б при зниженні JDK ... Припустимо, приклад такий різні, але ви розумієте.
ассілія

Це CAS якась стандартна абревіатура?
Аббас

1
Порівняйте і
нескінченний

4

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

Однак, якщо вам не потрібна ця додаткова функціональність, я пропоную використовувати звичайне volatileполе.


Отже, різниця полягає в їх виконанні. Якби різниці не було, ви ніколи не запропонували використовувати один за іншим.
BT

Вистава майже однакова. AtomicRefrence додає складності та використання пам'яті.
Пітер Лорі

@BT volatileПоле може бути використане як і будь-яке звичайне поле, тоді як доступ до значення у AtomicReferenceнеобхідному проходженні getта setметодах.
Девід Харкнесс

0

Іноді, навіть якщо ви використовуєте лише get і sets, 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;

Однак другий, швидше за все, буде видалений кимось випадково в майбутньому під час "чищення коду".

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.