Yanıtlar:
Kısa cevap: Hayır.
Gönderen java.util.concurrent.atomic
paket belgelerine. Alıntılamak:
Atomiklerin erişimleri ve güncellemeleri için bellek etkileri genellikle uçucular için olan kurallara uyar:
get
volatile
değişken okuma bellek etkilerine sahiptir .set
volatile
değişken yazma (atama) bellek etkilerine sahiptir .
Bu arada, bu belgeler çok iyi ve her şey açıklanıyor.
AtomicReference::lazySet
semantikler volatile
değ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 AtomicReference
get / set kullanmak, uçucu bir alanla (javadoc durumları gibi) aynı JMM semantiğine sahiptir , ancak AtomicReference
bir 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ı)AtomicReference
geçici bir referanstan daha zengin bir API sunar. Bir AtomicFieldUpdater
veya Java 9 a kullanarak uçucu referans için API'yi yeniden kazanabilirsiniz VarHandle
. sun.misc.Unsafe
Makasla koşmayı seviyorsanız düz olarak da ulaşabilirsiniz . AtomicReference
kendisi kullanılarak uygulanır Unsafe
.
Peki, birini diğerinden seçmek ne zaman iyidir:
AtomicReference
/ AtomicFieldUpdater
/ Unsafe
performans 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.
AtomicReference
dü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 volatile
alan kullanmanızı öneririm .
volatile
alan bir değer erişmek ise düzenli bir alan gibi kullanılabilir AtomicReference
giderek gerektiren get
ve set
yö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.