AtomicInteger lazySet vs. set

116

Apa perbedaan antara metode lazySetdan ? The dokumentasi tidak memiliki banyak untuk mengatakan tentang :setAtomicIntegerlazySet

Akhirnya disetel ke nilai yang diberikan.

Tampaknya nilai yang disimpan tidak akan langsung disetel ke nilai yang diinginkan, tetapi akan dijadwalkan untuk disetel di masa mendatang. Tapi, apa kegunaan praktis dari metode ini? Ada contoh?

Cheok Yan Cheng
sumber

Jawaban:

114

Dikutip langsung dari "JDK-6275329: Tambahkan metode lazySet ke kelas atom" :

Sebagai tindak lanjut JSR166 kecil terakhir untuk Mustang, kami menambahkan metode "lazySet" ke kelas Atom (AtomicInteger, AtomicReference, dll). Ini adalah metode khusus yang terkadang berguna saat menyempurnakan kode menggunakan struktur data non-pemblokiran. Semantiknya adalah bahwa penulisan dijamin tidak akan diurutkan ulang dengan penulisan sebelumnya, tetapi dapat diurutkan ulang dengan operasi berikutnya (atau secara ekuivalen, mungkin tidak terlihat oleh utas lain) hingga beberapa tindakan penulisan atau sinkronisasi volatil lainnya terjadi).

Kasus penggunaan utama adalah untuk meniadakan bidang node dalam struktur data non-pemblokiran semata-mata demi menghindari retensi sampah jangka panjang; ini berlaku jika tidak berbahaya jika utas lain melihat nilai bukan nol untuk sementara waktu, tetapi Anda ingin memastikan bahwa struktur pada akhirnya dapat diterapkan. Dalam kasus seperti itu, Anda bisa mendapatkan kinerja yang lebih baik dengan menghindari biaya penulisan volatil nol. Ada beberapa kasus penggunaan lain di sepanjang baris ini untuk atomics berbasis non-referensi juga, jadi metode ini didukung di semua kelas AtomicX.

Untuk orang-orang yang suka menganggap operasi ini dalam hal hambatan level mesin pada multiprosesor umum, lazySet menyediakan penghalang toko-toko sebelumnya (yang tidak dapat dioperasikan atau sangat murah pada platform saat ini), tetapi tidak ada penghalang muatan penyimpanan (yang biasanya merupakan bagian mahal dari penulisan volatile).

menguap
sumber
14
Bisakah seseorang membodohi kita semua? :(
Gaurav
14
Lazy adalah versi non-volatile (misalnya, perubahan status tidak dijamin akan terlihat oleh semua thread yang memiliki Atomic*cakupan).
menguap
63
Yang tidak saya mengerti adalah mengapa javadoc sangat miskin tentang itu.
Felipe
8
Saya yakin mereka akan segera mengubahnya. Boom boom.
MMJZ
3
bagi mereka yang ingin tahu lebih banyak tentang penghalang penyimpanan / beban dan mengapa penghalang toko-toko lebih murah daripada penghalang penyimpanan-beban. Berikut adalah artikel yang mudah dipahami tentang itu. mechanical-sympathy.blogspot.com/2011/07/…
Kin Cheung
15

lazySet dapat digunakan untuk komunikasi antar thread rmw, karena xchg bersifat atomic, sedangkan untuk visibilitas, ketika proses thread penulis mengubah lokasi baris cache, prosesor thread pembaca akan melihatnya di pembacaan berikutnya, karena protokol koherensi cache intel cpu akan menjamin LazySet berfungsi, tetapi baris cache akan diperbarui pada pembacaan berikutnya, sekali lagi, CPU harus cukup modern.

http://sc.tamu.edu/systems/eos/nehalem.pdf Untuk Nehalem yang merupakan platform multi-prosesor, prosesor memiliki kemampuan untuk "mengintip" (menguping) bus alamat untuk akses prosesor lain ke memori sistem dan ke cache internal mereka. Mereka menggunakan kemampuan pengintaian ini untuk menjaga agar cache internal mereka tetap konsisten baik dengan memori sistem maupun dengan cache di prosesor lain yang saling berhubungan. Jika melalui pengintaian, satu prosesor mendeteksi bahwa prosesor lain bermaksud untuk menulis ke lokasi memori yang saat ini telah di-cache dalam status Bersama, prosesor pengintai akan membatalkan blok cache-nya dan memaksanya untuk melakukan pengisian baris cache saat berikutnya mengakses lokasi memori yang sama .

oracle hotspot jdk untuk arsitektur cpu x86->

lazySet == unsafe.putOrderedLong == xchg rw (instruksi asm yang berfungsi sebagai penghalang lunak selama 20 siklus pada nehelem intel cpu)

pada x86 (x86_64) penghalang seperti itu jauh lebih murah dari segi kinerja daripada volatile atau AtomicLong getAndAdd,

Dalam satu produsen, satu skenario antrian konsumen, xchg soft barrier dapat memaksa baris kode sebelum lazySet (urutan + 1) untuk thread produsen terjadi SEBELUM kode thread konsumen yang akan mengkonsumsi (mengerjakan) data baru, tentu saja utas konsumen perlu memeriksa secara atomis bahwa urutan produsen bertambah tepat satu menggunakan bandingkanAndSet (urutan, urutan + 1).

Saya menelusuri setelah kode sumber Hotspot untuk menemukan pemetaan yang tepat dari lazySet ke kode cpp: http://hg.openjdk.java.net/jdk7/jdk7/hotspot/file/9b0ca45cd756/src/share/vm/prims/unsafe. cpp Unsafe_setOrderedLong -> definisi SET_FIELD_VOLATILE -> OrderAccess: release_store_fence. Untuk x86_64, OrderAccess: release_store_fence didefinisikan sebagai menggunakan instruksi xchg.

Anda dapat melihat bagaimana tepatnya didefinisikan di jdk7 (doug lea bekerja pada beberapa hal baru untuk JDK 8): http://hg.openjdk.java.net/jdk7/jdk7/hotspot/file/4fc084dac61e/src/os_cpu/ linux_x86 / vm / orderAccess_linux_x86.inline.hpp

Anda juga dapat menggunakan hdis untuk membongkar perakitan kode lazySet.

Ada pertanyaan terkait lainnya: Apakah kita membutuhkan mfence saat menggunakan xchg

daging babi
sumber
5
Sulit untuk memahami apa yang Anda maksud di sini. Bisakah Anda menjelaskan maksud Anda?
Paul Bellora
3
"lazySet == unsafe.putOrderedLong == xchg rw (instruksi asm yang berfungsi sebagai penghalang lunak dengan biaya 20 siklus pada nehelem intel cpu) pada x86 (x86_64) penghalang semacam itu jauh lebih murah dari segi performa daripada volatile atau AtomicLong getAndAdd" -> Ini tidak benar sepanjang pengetahuan saya. lazySet / putOrdered adalah MOV ke alamat, itulah sebabnya buku masak JMM mendeskripsikannya sebagai no-op pada x86.
Nitsan Wakart
11

Diskusi yang lebih luas tentang asal dan kegunaan lazySet dan putOrdered yang mendasari dapat ditemukan di sini: http://psy-lob-saw.blogspot.co.uk/2012/12/atomiclazyset-is-performance-win-for.html

Untuk meringkas: lazySet adalah penulisan volatile yang lemah dalam arti bahwa ia bertindak sebagai penyimpanan-penyimpanan dan bukan pagar penyimpanan-penyimpanan. Ini bermuara pada lazySet menjadi JIT yang dikompilasi menjadi instruksi MOV yang tidak dapat diurutkan ulang oleh kompilator daripada instruksi yang jauh lebih mahal yang digunakan untuk set volatil.

Saat membaca nilai, Anda selalu berakhir dengan membaca volatile (dengan Atomic * .get () dalam hal apa pun).

lazySet menawarkan kepada satu penulis mekanisme penulisan volatil yang konsisten, yaitu sah bagi satu penulis untuk menggunakan lazySet untuk menaikkan penghitung, beberapa utas yang menaikkan penghitung yang sama harus menyelesaikan penulisan yang bersaing menggunakan CAS, yang persis terjadi di bawah sampul Atomic * untuk incAndGet.

Nitsan Wakart
sumber
persis, mengapa kita tidak bisa mengatakan bahwa ini adalah sederhana StoreStorepenghalang, tetapi tidak seorang StoreLoad?
Eugene
8

Dari ringkasan paket atomik serentak

lazySet memiliki efek memori saat menulis (menugaskan) variabel volatil kecuali bahwa ia mengizinkan pengurutan ulang dengan tindakan memori berikutnya (tetapi tidak sebelumnya) yang tidak dengan sendirinya memaksakan batasan pengurutan ulang dengan penulisan non-volatil biasa. Di antara konteks penggunaan lainnya, lazySet dapat diterapkan saat meniadakan, demi pengumpulan sampah, referensi yang tidak pernah diakses lagi.

Jika Anda penasaran dengan lazySet maka Anda juga berhutang penjelasan lain kepada diri Anda sendiri

Efek memori untuk akses dan pembaruan atomics umumnya mengikuti aturan untuk volatil, seperti yang dinyatakan di bagian 17.4 Spesifikasi Bahasa Java ™.

get memiliki efek memori membaca variabel volatil.

set memiliki efek memori untuk menulis (menetapkan) variabel volatil.

lazySet memiliki efek memori saat menulis (menugaskan) variabel volatil kecuali bahwa ia mengizinkan pengurutan ulang dengan tindakan memori berikutnya (tetapi tidak sebelumnya) yang tidak dengan sendirinya memaksakan batasan pengurutan ulang dengan penulisan non-volatil biasa. Di antara konteks penggunaan lainnya, lazySet dapat diterapkan saat meniadakan, demi pengumpulan sampah, referensi yang tidak pernah diakses lagi.

weakCompareAndSet secara atomis membaca dan menulis variabel secara kondisional tetapi tidak membuat pengurutan yang terjadi sebelum, jadi tidak memberikan jaminan sehubungan dengan pembacaan dan penulisan sebelumnya atau berikutnya dari variabel apa pun selain target dari weakCompareAndSet.

bandingkanAndSet dan semua operasi baca-dan-perbarui lainnya seperti getAndIncrement memiliki efek memori untuk membaca dan menulis variabel volatil.

Ajeet Ganga
sumber
4

Berikut adalah pemahaman saya, perbaiki saya jika saya salah: Anda dapat menganggapnya lazySet()sebagai "semi" volatile: pada dasarnya ini adalah variabel non-volatile dalam hal membaca oleh utas lain, yaitu nilai yang ditetapkan oleh lazySet mungkin tidak terlihat oleh orang lain benang. Tapi itu menjadi tidak stabil ketika operasi tulis lain terjadi (mungkin dari utas lain). Satu-satunya dampak dari lazySet yang dapat saya bayangkan adalah compareAndSet. Jadi jika Anda menggunakan lazySet(), get()dari utas lain mungkin masih mendapatkan nilai lama, tetapi compareAndSet()akan selalu memiliki nilai baru karena ini adalah operasi tulis.

jyluo.dll
sumber
1
bukankah maksudmu compareAndSet?
Dave Moten
2

Re: mencoba untuk membodohinya -

Anda dapat menganggap ini sebagai cara untuk memperlakukan bidang yang mudah menguap seolah-olah tidak mudah menguap untuk operasi penyimpanan tertentu (misalnya: ref = null;).

Itu tidak sepenuhnya akurat, tetapi seharusnya cukup bahwa Anda dapat membuat keputusan antara "OK, saya benar-benar tidak peduli" dan "Hmm, biarkan saya memikirkannya sebentar".

Paul Mclachlan
sumber