Referensi mudah menguap vs AtomicReference


135

Apakah ada perbedaan antara volatilereferensi Obyek dan AtomicReferencejika saya hanya akan menggunakan get()dan set()-metode dari AtomicReference?

Jawaban:


114

Jawaban singkatnya adalah: Tidak.

Dari java.util.concurrent.atomicdokumentasi paket. Kutipan:

Efek memori untuk akses dan pembaruan atom umumnya mengikuti aturan untuk volatil:

  • getmemiliki efek memori membaca volatilevariabel.
  • setmemiliki efek memori menulis (menugaskan) volatilevariabel.

Omong-omong, dokumentasi itu sangat bagus dan semuanya dijelaskan.


AtomicReference::lazySetadalah operasi yang lebih baru (Java 6+) yang diperkenalkan yang memiliki semantik yang tidak dapat diraih melalui volatilevariabel. Lihat posting ini untuk informasi lebih lanjut.


11
Dan jawaban yang lebih panjang adalah?
Julien Grenier

Sepakat. Kami setidaknya membutuhkan tautan.
Julien Chastang


42

Tidak, tidak ada.

Kekuatan tambahan yang disediakan oleh AtomicReference adalah metode compareAndSet () dan teman-teman. Jika Anda tidak memerlukan metode itu, referensi yang mudah menguap menyediakan semantik yang sama dengan AtomicReference.set () dan .get ().


14

Ada beberapa perbedaan dan pengorbanan:

  1. Menggunakan AtomicReferenceget / set memiliki semantik JMM yang sama dengan bidang volatil (seperti status javadoc), tetapi AtomicReferencepembungkus di sekitar referensi, sehingga setiap akses ke bidang melibatkan pengejaran penunjuk lebih lanjut .

  2. The jejak memori dikalikan (dengan asumsi lingkungan OOP dikompresi, yang berlaku untuk sebagian besar VMS):

    • ref volatile = 4b
    • AtomicReference = 4b + 16b (header objek 12b + bidang ref 4b)
  3. AtomicReferencemenawarkan 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.Unsafejika Anda suka berlari dengan gunting. AtomicReferenceitu sendiri diimplementasikan menggunakan Unsafe.

Jadi, kapan sebaiknya memilih satu di antara yang lain:

  • Hanya butuh get / set? Stick dengan bidang yang mudah menguap, solusi paling sederhana dan overhead terendah.
  • Perlu fungsionalitas tambahan? Jika ini adalah bagian sensitif dari kinerja (kecepatan / memori) dari kode Anda, tentukan pilihan antara AtomicReference/ AtomicFieldUpdater/ di Unsafemana 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.

7

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.


13
"Kode sumber JDK adalah salah satu cara terbaik untuk menjawab kebingungan seperti ini" => Saya tidak setuju - javadoc (yang merupakan kontrak kelas) adalah cara terbaik. Apa yang Anda temukan dalam kode menjawab pertanyaan untuk implementasi spesifik tetapi kode dapat berubah.
assylias

4
Misalnya variabel ini dalam hashmap volatile di JDK 6 tetapi tidak volatile lagi di Java 7. Apakah Anda mendasarkan kode Anda pada fakta bahwa variabel volatile, itu akan rusak ketika mem-ugrading JDK Anda ... Memang contohnya adalah berbeda tetapi Anda mendapatkan intinya.
assylias

Apakah itu CAS singkatan standar?
abbas

1
Bandingkan dan Tukar =)
tak berujung

4

AtomicReferencemenyediakan 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 volatilebidang yang sederhana .


Jadi perbedaannya adalah pada kinerja mereka. Jika tidak ada perbedaan, Anda tidak akan pernah menyarankan untuk menggunakan salah satunya.
BT

Kinerjanya hampir sama. Sebuah AtomicRefrence menambah kompleksitas dan penggunaan memori.
Peter Lawrey

@BT volatileBidang dapat digunakan seperti bidang biasa mana pun mengakses nilai dalam AtomicReferencemembutuhkan melalui getdan setmetode.
David Harkness

0

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".

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.