Yanıtlar:
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 .
Birkaç farklılık ve ödünleşim vardır:
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 .
Bellek alanı çarpılır (en VM için geçerli olan bir sıkıştırılmış cepten ortamı, varsayılarak):
AtomicReference = 4b + 16b (12b nesne başlığı + 4b ref alanı)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:
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.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.
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 .
volatilealan bir değer erişmek ise düzenli bir alan gibi kullanılabilir AtomicReferencegiderek gerektiren getve setyöntemler.
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.