Kapan kita menggunakan AtomicReference
?
Apakah diperlukan untuk membuat objek di semua program multithread?
Berikan contoh sederhana di mana AtomicReference harus digunakan.
sumber
Kapan kita menggunakan AtomicReference
?
Apakah diperlukan untuk membuat objek di semua program multithread?
Berikan contoh sederhana di mana AtomicReference harus digunakan.
Referensi atom harus digunakan dalam pengaturan di mana Anda perlu melakukan operasi atom sederhana (yaitu thread-safe , non-trivial) pada referensi, di mana sinkronisasi berbasis monitor tidak tepat. Misalkan Anda ingin memeriksa untuk melihat apakah bidang tertentu hanya jika keadaan objek tetap saat Anda terakhir memeriksa:
AtomicReference<Object> cache = new AtomicReference<Object>();
Object cachedValue = new Object();
cache.set(cachedValue);
//... time passes ...
Object cachedValueToUpdate = cache.get();
//... do some work to transform cachedValueToUpdate into a new version
Object newValue = someFunctionOfOld(cachedValueToUpdate);
boolean success = cache.compareAndSet(cachedValue,cachedValueToUpdate);
Karena semantik referensi atom, Anda dapat melakukan ini bahkan jika cache
objek dibagi di antara utas, tanpa menggunakan synchronized
. Secara umum, Anda lebih baik menggunakan sinkronisasi atau java.util.concurrent
kerangka daripada telanjang Atomic*
kecuali Anda tahu apa yang Anda lakukan.
Dua referensi pohon mati yang bagus yang akan memperkenalkan Anda pada topik ini:
Perhatikan bahwa (saya tidak tahu apakah ini selalu benar) tugas referensi (yaitu =
) itu sendiri adalah atomik (memperbarui tipe 64-bit primitif suka long
atau double
mungkin tidak menjadi atom; tetapi memperbarui referensi selalu atom, meskipun itu 64 bit ) tanpa secara eksplisit menggunakan Atomic*
.
Lihat Spesifikasi Bahasa Jawa 3ed, Bagian 17.7 .
AtomicReference
Anda harus menandai variabelvolatile
karena sementara runtime menjamin bahwa penugasan referensi adalah atom, kompiler dapat melakukan optimasi dengan asumsi bahwa variabel tidak sedang dimodifikasi oleh utas lainnya.AtomicReference
"; jika Anda sedang menggunakannya, maka saran saya akan pergi ke arah yang berlawanan dan menandainyafinal
sehingga compiler dapat mengoptimalkannya.Referensi atom sangat ideal untuk digunakan ketika Anda perlu berbagi dan mengubah keadaan objek abadi antara beberapa utas. Itu adalah pernyataan yang sangat padat jadi saya akan memecahnya sedikit.
Pertama, objek abadi adalah objek yang secara efektif tidak berubah setelah konstruksi. Seringkali metode objek yang tidak dapat diubah mengembalikan instance baru dari kelas yang sama. Beberapa contoh termasuk kelas pembungkus Long dan Double, serta String, hanya untuk beberapa nama. (Berdasarkan Pemrograman Concurrency pada JVM objek abadi adalah bagian penting dari concurrency modern).
Selanjutnya, mengapa AtomicReference lebih baik daripada objek yang mudah menguap untuk berbagi nilai bersama itu. Contoh kode sederhana akan menunjukkan perbedaannya.
Setiap kali Anda ingin memodifikasi string yang dirujuk oleh bidang volatil itu berdasarkan nilai saat ini, Anda harus terlebih dahulu mendapatkan kunci pada objek itu. Ini mencegah beberapa utas lainnya masuk saat itu dan mengubah nilai di tengah rangkaian string baru. Kemudian ketika utas Anda kembali, Anda akan merusak pekerjaan utas lainnya. Tapi jujur kode itu akan berfungsi, itu terlihat bersih, dan itu akan membuat kebanyakan orang senang.
Sedikit masalah. Itu lambat. Terutama jika ada banyak pertengkaran Obyek kunci itu. Itu karena sebagian besar kunci memerlukan panggilan sistem OS, dan utas Anda akan diblokir dan secara konteks dialihkan dari CPU untuk memberi jalan bagi proses lain.
Opsi lainnya adalah menggunakan AtomicRefrence.
Sekarang mengapa ini lebih baik? Jujur kode itu sedikit kurang bersih dari sebelumnya. Tetapi ada sesuatu yang sangat penting yang terjadi di bawah tenda di AtomicRefrence, yaitu membandingkan dan menukar. Ini adalah instruksi CPU tunggal, bukan panggilan OS, yang membuat saklar terjadi. Itu adalah instruksi tunggal pada CPU. Dan karena tidak ada kunci, tidak ada saklar konteks dalam kasus di mana kunci dijalankan yang menghemat lebih banyak waktu!
Tangkapannya adalah, untuk AtomicReferences, ini tidak menggunakan panggilan .equals (), melainkan perbandingan == untuk nilai yang diharapkan. Jadi pastikan yang diharapkan adalah objek aktual yang dikembalikan dari get in the loop.
sumber
worked
untuk mendapatkan semantik yang sama.Berikut ini adalah kasus penggunaan untuk AtomicReference:
Pertimbangkan kelas ini yang bertindak sebagai rentang angka, dan menggunakan variabel AtmomicInteger individual untuk mempertahankan batas angka bawah dan atas.
Baik setLower dan setUpper adalah urutan centang lalu tindakan, tetapi keduanya tidak menggunakan penguncian yang memadai untuk membuatnya menjadi atom. Jika rentang nomor berlaku (0, 10), dan satu utas memanggil setLower (5) sedangkan utas lainnya memanggil setUpper (4), dengan beberapa waktu sial keduanya akan melewati pemeriksaan di setter dan kedua modifikasi akan diterapkan. Hasilnya adalah bahwa rentang sekarang memegang (5, 4) keadaan tidak valid. Jadi sementara AtomicIntegers yang mendasarinya adalah thread-safe, kelas komposit tidak. Ini dapat diperbaiki dengan menggunakan AtomicReference daripada menggunakan AtomicIntegers individu untuk batas atas dan bawah.
sumber
Anda dapat menggunakan AtomicReference saat menerapkan kunci optimis. Anda memiliki objek yang dibagikan dan Anda ingin mengubahnya dari lebih dari 1 utas.
Seperti utas lain yang mungkin telah memodifikasinya dan / dapat memodifikasi antara 2 langkah ini. Anda perlu melakukannya dalam operasi atom. Di sinilah AtomicReference dapat membantu
sumber
Berikut ini adalah use case yang sangat sederhana dan tidak ada hubungannya dengan keamanan thread.
Untuk berbagi objek antara permintaan lambda,
AtomicReference
ini adalah opsi :Saya tidak mengatakan ini adalah desain yang baik atau apa pun (itu hanya contoh sepele), tetapi jika Anda memiliki kasing di mana Anda perlu berbagi objek antara permintaan lambda,
AtomicReference
adalah pilihan.Bahkan Anda dapat menggunakan objek apa pun yang memegang referensi, bahkan Koleksi yang hanya memiliki satu item. Namun, AtomicReference sangat cocok.
sumber
Saya tidak akan banyak bicara. Rekan-rekan saya yang terhormat telah memberikan masukan berharga mereka.Kode berjalan yang lengkap pada akhir blog ini akan menghilangkan kebingungan. Ini tentang program pemesanan kursi film kecil dalam skenario multi-utas.
Beberapa fakta dasar yang penting adalah sebagai berikut. 1> Berbagai utas hanya dapat bersaing sebagai contoh dan variabel anggota statis di ruang tumpukan. 2> Volatile baca atau tulis sepenuhnya atom dan serial / terjadi sebelumnya dan hanya dilakukan dari memori. Dengan mengatakan ini, saya maksudkan bahwa setiap pembacaan akan mengikuti tulisan sebelumnya dalam memori. Dan setiap tulisan akan mengikuti pembacaan sebelumnya dari memori. Jadi utas apa pun yang bekerja dengan volatil akan selalu melihat nilai paling baru. AtomicReference menggunakan properti volatil ini.
Berikut adalah beberapa kode sumber AtomicReference. AtomicReference mengacu pada referensi objek. Referensi ini adalah variabel anggota yang mudah menguap dalam contoh AtomicReference seperti di bawah ini.
dapatkan () cukup kembalikan nilai terbaru dari variabel (seperti halnya volatil dengan cara "terjadi sebelum").
Berikut ini adalah metode paling penting dari AtomicReference.
Metode compareAndSet (mengharapkan, memperbarui) memanggil metode compareAndSwapObject () dari kelas Java yang tidak aman. Metode panggilan tidak aman ini memanggil panggilan asli, yang memanggil satu instruksi ke prosesor. "harapkan" dan "perbarui" setiap referensi sebuah objek.
Jika dan hanya jika variabel anggota instance AtomicReference "nilai" merujuk ke objek yang sama disebut oleh "ekspektasi", "pembaruan" ditugaskan ke variabel instance ini sekarang, dan "benar" dikembalikan. Atau yang lain, false dikembalikan. Semuanya dilakukan secara atom. Tidak ada utas lain yang dapat mencegahnya. Karena ini adalah operasi prosesor tunggal (keajaiban arsitektur komputer modern), seringkali lebih cepat daripada menggunakan blok yang disinkronkan. Tapi ingat bahwa ketika beberapa variabel perlu diperbarui secara atom, AtomicReference tidak akan membantu.
Saya ingin menambahkan kode berjalan yang lengkap, yang dapat dijalankan di gerhana. Itu akan menghapus banyak kebingungan. Di sini 22 pengguna (utasku) mencoba memesan 20 kursi. Berikut ini adalah cuplikan kode diikuti oleh kode lengkap.
Cuplikan kode tempat 22 pengguna mencoba memesan 20 kursi.
Berikut ini adalah kode berjalan lengkap.
sumber
AtomicReference adalah cara fleksibel untuk memperbarui nilai variabel secara atomis tanpa menggunakan sinkronisasi.
AtomicReference
mendukung pemrograman thread-safe bebas kunci pada variabel tunggal.Ada beberapa cara untuk mencapai keselamatan Thread dengan API bersamaan tingkat tinggi . Variabel atom adalah salah satu dari beberapa opsi.
Lock
objek mendukung idiom pengunci yang menyederhanakan banyak aplikasi bersamaan.Executors
mendefinisikan API tingkat tinggi untuk meluncurkan dan mengelola utas. Implementasi pelaksana yang disediakan oleh java.util.concurrent menyediakan manajemen kumpulan thread yang cocok untuk aplikasi skala besar.Koleksi bersamaan membuatnya lebih mudah untuk mengelola koleksi data yang besar, dan dapat sangat mengurangi kebutuhan sinkronisasi.
Variabel atom memiliki fitur yang meminimalkan sinkronisasi dan membantu menghindari kesalahan konsistensi memori.
Kode contoh dengan
AtomicReference
:Anda tidak harus menggunakan
AtomicReference
semua program multi-utas.Jika Anda ingin menjaga satu variabel, gunakan
AtomicReference
. Jika Anda ingin menjaga blok kode, gunakan konstruksi lain sepertiLock
/synchronized
dll.sumber
Contoh sederhana lainnya adalah melakukan modifikasi safe-thread pada objek sesi.
Sumber: http://www.ibm.com/developerworks/library/j-jtp09238/index.html
sumber