Java geçici referansı ile AtomicReference karşılaştırması


135

Bir arasında herhangi bir fark var mı volatileNesne referans ve AtomicReferenceben sadece kullanmak durumunda get()ve set()gelen -Kullanılan AtomicReference?

Yanıtlar:


114

Kısa cevap: Hayır.

Gönderen java.util.concurrent.atomicpaket belgelerine. Alıntılamak:

Atomiklerin erişimleri ve güncellemeleri için bellek etkileri genellikle uçucular için olan kurallara uyar:

  • getvolatiledeğişken okuma bellek etkilerine sahiptir .
  • setvolatiledeğişken yazma (atama) bellek etkilerine sahiptir .

Bu arada, bu belgeler çok iyi ve her şey açıklanıyor.


AtomicReference::lazySetsemantikler volatiledeğişkenler aracılığıyla erişilemeyen daha yeni (Java 6+) bir işlemdir . Daha fazla bilgi için bu gönderiye bakın .


11
Ve daha uzun cevap ne olurdu?
Julien Grenier

Kabul. En azından bir bağlantıya ihtiyacımız var.
Julien Chastang


42

Hayır yok.

AtomicReference tarafından sağlanan ek güç, CompareAndSet () yöntemi ve arkadaşlarıdır. Bu yöntemlere ihtiyacınız yoksa, geçici bir başvuru AtomicReference.set () ve .get () ile aynı semantiği sağlar.


14

Birkaç farklılık ve ödünleşim vardır:

  1. Bir AtomicReferenceget / set kullanmak, uçucu bir alanla (javadoc durumları gibi) aynı JMM semantiğine sahiptir , ancak AtomicReferencebir referansın etrafındaki bir sarıcıdır, bu nedenle alana herhangi bir erişim daha fazla işaretçi kovalaması içerir .

  2. Bellek alanı çarpılır (en VM için geçerli olan bir sıkıştırılmış cepten ortamı, varsayılarak):

    • uçucu ref = 4b
    • AtomicReference = 4b + 16b (12b nesne başlığı + 4b ref alanı)
  3. AtomicReferencegeçici bir referanstan daha zengin bir API sunar. Bir AtomicFieldUpdaterveya Java 9 a kullanarak uçucu referans için API'yi yeniden kazanabilirsiniz VarHandle. sun.misc.UnsafeMakasla koşmayı seviyorsanız düz olarak da ulaşabilirsiniz . AtomicReferencekendisi kullanılarak uygulanır Unsafe.

Peki, birini diğerinden seçmek ne zaman iyidir:

  • Sadece almanız / ayarlamanız mı gerekiyor? Uçucu bir alan, en basit çözüm ve en düşük ek yük ile sadık kalın.
  • Ek işlevselliğe mi ihtiyacınız var? Bu, kodunuzun performansa (hız / bellek ek yükü) duyarlı bir parçasıysa, okunabilirlikle ödeme yapma eğiliminiz olan AtomicReference/ AtomicFieldUpdater/ Unsafeperformans artışı için risk arasında seçim yapın. Bu hassas bir alan değilse sadece gidin AtomicReference. Kütüphane yazarları, hedeflenen JDK'lara, beklenen API kısıtlamalarına, bellek kısıtlamalarına vb. Bağlı olarak genellikle bu yöntemlerin bir karışımını kullanır.

7

JDK kaynak kodu , bu tür karışıklıklara cevap vermenin en iyi yollarından biridir. AtomicReference içindeki koda bakarsanız, nesne depolama için bir volatie değişkeni kullanır.

private volatile V value;

Açıkçası AtomicReference üzerinde get () ve set () kullanacaksanız, bu değişken bir değişken kullanmak gibidir. Ancak diğer okuyucuların yorumladığı gibi, AtomicReference ek CAS semantiği sağlar. Bu nedenle, önce CAS semantiği isteyip istemediğinize karar verin ve sadece AtomicReference kullanın.


13
"JDK kaynak kodu böyle karışıklıklara cevap vermenin en iyi yollarından biridir" => Mutlaka aynı fikirde değilim - javadoc (sınıfın sözleşmesi) en iyi yoldur. Kodda bulduklarınız belirli bir uygulama için soruyu yanıtlar, ancak kod değişebilir.
assylias

4
Örneğin hashmap'teki bu değişken JDK 6'da değişken ancak artık Java 7'de geçici değil. Kodunuzu değişkenin değişken olduğu gerçeğine dayandırdınız mı, JDK'nızı taşırken kırılmış olacak ... Kabul etmek gerekirse örnek farklı ama sen anladın.
assylias

Bu CAS bazı standart kısaltmalar mıdır?
abbas

1
Karşılaştırma ve Takas =)
sonsuz

4

AtomicReferencedüz uçucu bir değişkenin sağlamadığı ek işlevsellik sağlar. API Javadoc'u okuduğunuzda bunu bileceksiniz, ancak aynı zamanda bazı işlemler için yararlı olabilecek bir kilit de sağlar.

Ancak, bu ek işlevselliğe ihtiyacınız olmadığı sürece düz bir volatilealan kullanmanızı öneririm .


Öyleyse, fark performanslarında. Hiçbir fark olmasaydı, birini diğerinden daha fazla kullanmanızı önermezsiniz.
BT

Performans hemen hemen aynı. Bir AtomicRefrence karmaşıklık ve bellek kullanımı ekler.
Peter Lawrey

@BT bir volatilealan bir değer erişmek ise düzenli bir alan gibi kullanılabilir AtomicReferencegiderek gerektiren getve setyöntemler.
David Harkness

0

Bazen sadece get ve setleri kullansanız bile, AtomicReference iyi bir seçim olabilir:

Uçucu olan örnek:

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 ile uygulama size ücretsiz bir kopyala yazma senkronizasyonu sağlar.

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
  }
}

Yer değiştirirseniz yine de uygun bir kopyaya sahip olabileceğiniz söylenebilir:

Status status = statusWrapper.get();

ile:

Status statusCopy = status;

Ancak ikincisinin gelecekte "kod temizliği" sırasında yanlışlıkla kaldırılması daha olasıdır.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.