Jawaban:
Jawaban singkatnya adalah: Tidak.
Dari java.util.concurrent.atomic
dokumentasi paket. Kutipan:
Efek memori untuk akses dan pembaruan atom umumnya mengikuti aturan untuk volatil:
get
memiliki efek memori membacavolatile
variabel.set
memiliki efek memori menulis (menugaskan)volatile
variabel.
Omong-omong, dokumentasi itu sangat bagus dan semuanya dijelaskan.
AtomicReference::lazySet
adalah operasi yang lebih baru (Java 6+) yang diperkenalkan yang memiliki semantik yang tidak dapat diraih melalui volatile
variabel. Lihat posting ini untuk informasi lebih lanjut.
Ada beberapa perbedaan dan pengorbanan:
Menggunakan AtomicReference
get / set memiliki semantik JMM yang sama dengan bidang volatil (seperti status javadoc), tetapi AtomicReference
pembungkus di sekitar referensi, sehingga setiap akses ke bidang melibatkan pengejaran penunjuk lebih lanjut .
The jejak memori dikalikan (dengan asumsi lingkungan OOP dikompresi, yang berlaku untuk sebagian besar VMS):
AtomicReference
= 4b + 16b (header objek 12b + bidang ref 4b)AtomicReference
menawarkan API yang lebih kaya daripada referensi yang tidak stabil. Anda bisa mendapatkan kembali API untuk referensi yang mudah menguap dengan menggunakan AtomicFieldUpdater
, atau dengan Java 9 a VarHandle
. Anda juga bisa meraih lurus sun.misc.Unsafe
jika Anda suka berlari dengan gunting. AtomicReference
itu sendiri diimplementasikan menggunakan Unsafe
.
Jadi, kapan sebaiknya memilih satu di antara yang lain:
AtomicReference
/ AtomicFieldUpdater
/ di Unsafe
mana Anda cenderung membayar dalam keterbacaan dan risiko untuk kenaikan kinerja Anda. Jika ini bukan area sensitif hanya untuk AtomicReference
. Penulis perpustakaan biasanya menggunakan campuran metode ini tergantung pada JDK yang ditargetkan, pembatasan API yang diharapkan, kendala memori dan sebagainya.Kode sumber JDK adalah salah satu cara terbaik untuk menjawab kebingungan seperti ini. Jika Anda melihat kode di AtomicReference, ia menggunakan variabel volatie untuk penyimpanan objek.
private volatile V value;
Jadi, jelas jika Anda hanya akan menggunakan get () dan set () pada AtomicReference itu seperti menggunakan variabel volatile. Tetapi seperti komentar pembaca lain, AtomicReference menyediakan semantik CAS tambahan. Jadi, pertama-tama putuskan apakah Anda ingin CAS semantik atau tidak, dan jika Anda melakukannya, gunakan AtomicReference.
AtomicReference
menyediakan fungsionalitas tambahan yang tidak disediakan oleh variabel volatil sederhana. Karena Anda telah membaca API Javadoc, Anda akan mengetahui hal ini, tetapi juga menyediakan kunci yang dapat berguna untuk beberapa operasi.
Namun, kecuali Anda membutuhkan fungsionalitas tambahan ini, saya sarankan Anda menggunakan volatile
bidang yang sederhana .
volatile
Bidang dapat digunakan seperti bidang biasa mana pun mengakses nilai dalam AtomicReference
membutuhkan melalui get
dan set
metode.
Terkadang bahkan jika Anda hanya menggunakan get and set, AtomicReference mungkin merupakan pilihan yang baik:
Contoh dengan volatile:
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
}
}
Implementasi dengan AtomicReference akan memberi Anda sinkronisasi copy-on-write secara gratis.
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
}
}
Orang mungkin mengatakan bahwa Anda masih bisa memiliki salinan yang tepat jika Anda mengganti:
Status status = statusWrapper.get();
dengan:
Status statusCopy = status;
Namun yang kedua lebih mungkin dihapus oleh seseorang secara tidak sengaja di masa depan selama "pembersihan kode".