volatile
memiliki semantik untuk visibilitas memori. Pada dasarnya, nilai volatile
bidang menjadi terlihat oleh semua pembaca (utas lainnya khususnya) setelah operasi penulisan selesai di atasnya. Tanpa volatile
, pembaca dapat melihat beberapa nilai yang tidak diperbarui.
Untuk menjawab pertanyaan Anda: Ya, saya menggunakan volatile
variabel untuk mengontrol apakah beberapa kode melanjutkan loop. Loop menguji volatile
nilai dan melanjutkan jika itu true
. Kondisi ini dapat diatur false
dengan memanggil metode "stop". Loop melihat false
dan berakhir ketika menguji nilai setelah metode berhenti menyelesaikan eksekusi.
Buku " Java Concurrency in Practice ," yang sangat saya rekomendasikan, memberikan penjelasan yang baik tentang volatile
. Buku ini ditulis oleh orang yang sama yang menulis artikel IBM yang dirujuk dalam pertanyaan (pada kenyataannya, ia mengutip bukunya di bagian bawah artikel itu). Penggunaan saya atas volatile
apa yang oleh artikelnya disebut "bendera status pola 1".
Jika Anda ingin mempelajari lebih lanjut tentang cara volatile
kerjanya di bawah tenda, bacalah tentang model memori Java . Jika Anda ingin melampaui level itu, lihat buku arsitektur komputer yang bagus seperti Hennessy & Patterson dan baca tentang koherensi cache dan konsistensi cache.
volatile
yang datang dengan Java Memory Model baru yang didefinisikan dalam JSR 133: bahwa ketika sebuah thread membaca sebuahvolatile
variabel, ia melihat tidak hanya nilai yang terakhir ditulis untuknya oleh beberapa thread lain, tetapi juga semua yang lain menulis ke variabel lain yang terlihat di utas lainnya pada saatvolatile
penulisan. Lihat jawaban ini dan referensi ini ."... pengubah volatil menjamin bahwa utas apa pun yang membaca bidang akan melihat nilai yang paling baru ditulis." - Josh Bloch
Jika Anda berpikir untuk menggunakan
volatile
, bacalah paketjava.util.concurrent
yang berkaitan dengan perilaku atom.Posting Wikipedia pada Pola Singleton menunjukkan volatile digunakan.
sumber
volatile
dan keduanyasynchronized
?volatile
contoh kata lebih lama. Itu dapat ditemukan dalam versi yang diarsipkan .void
dan keduanyapublic
".Poin penting tentang
volatile
:synchronized
danvolatile
dan kunci Java .synchronized
variabel. Menggunakansynchronized
kata kunci dengan variabel adalah ilegal dan akan menghasilkan kesalahan kompilasi. Alih-alih menggunakansynchronized
variabel di Jawa, Anda bisa menggunakanvolatile
variabel java , yang akan menginstruksikan thread JVM untuk membaca nilaivolatile
variabel dari memori utama dan jangan cache secara lokal.volatile
kata kunci.sumber
Contoh penggunaan
volatile
:Kami membuat contoh dengan malas pada saat permintaan pertama datang.
Jika kita tidak membuat
_instance
variabelvolatile
maka Thread yang membuat instance dariSingleton
tidak dapat berkomunikasi ke thread lain. Jadi jika Thread A membuat Singleton instance dan setelah penciptaan, CPU rusak dll, semua utas lainnya tidak akan dapat melihat nilai_instance
bukan nol dan mereka akan percaya itu masih ditugaskan nol.Mengapa ini terjadi? Karena utas pembaca tidak melakukan penguncian dan sampai utas penulis keluar dari blok yang disinkronkan, memori tidak akan disinkronkan dan nilai
_instance
tidak akan diperbarui di memori utama. Dengan kata kunci Volatile di Java, ini ditangani oleh Java sendiri dan pembaruan tersebut akan terlihat oleh semua utas pembaca.Contoh penggunaan tanpa volatile:
Kode di atas tidak aman untuk thread. Meskipun memeriksa nilai instance sekali lagi di dalam blok yang disinkronkan (untuk alasan kinerja), kompiler JIT dapat mengatur ulang bytecode sedemikian rupa sehingga referensi ke instance diatur sebelum konstruktor menyelesaikan eksekusi. Ini berarti metode getInstance () mengembalikan objek yang mungkin belum diinisialisasi sepenuhnya. Untuk membuat kode-aman, kata kunci volatile dapat digunakan sejak Java 5 untuk variabel instan. Variabel yang ditandai sebagai volatil hanya dapat dilihat oleh utas lainnya setelah konstruktor objek telah menyelesaikan eksekusi sepenuhnya.
Sumber
volatile
penggunaan di Jawa :Iterator gagal-cepat biasanya diimplementasikan menggunakan
volatile
penghitung pada objek daftar.Iterator
dibuat, nilai saat ini dari penghitung tertanam diIterator
objek.Iterator
operasi dilakukan, metode ini membandingkan dua nilai penghitung dan melempar aConcurrentModificationException
jika mereka berbeda.Implementasi iterator gagal-aman biasanya ringan. Mereka biasanya mengandalkan properti dari struktur data implementasi daftar tertentu. Tidak ada pola umum.
sumber
private static final Singleton _instance;
juga.volatile
sangat berguna untuk menghentikan utas.Bukan berarti Anda harus menulis utas sendiri, Java 1.6 memiliki banyak kumpulan utas yang bagus. Tetapi jika Anda yakin membutuhkan utas, Anda harus tahu cara menghentikannya.
Pola yang saya gunakan untuk utas adalah:
Di segmen kode di atas, utas pembacaan
close
di loop sementara berbeda dari yang memanggilclose()
. Tanpa volatile, utas yang menjalankan loop mungkin tidak akan pernah melihat perubahan ditutup.Perhatikan bagaimana tidak perlu sinkronisasi
sumber
volatile
kata kunci, dan sepertinya selalu berfungsi dengan baik.Salah satu contoh umum untuk menggunakan
volatile
adalah menggunakanvolatile boolean
variabel sebagai bendera untuk mengakhiri utas. Jika Anda telah memulai utas, dan Anda ingin dapat dengan aman menghentikannya dari utas lain, Anda dapat meminta utas secara berkala memeriksa bendera. Untuk menghentikannya, atur bendera ke true. Dengan membuat benderavolatile
, Anda dapat memastikan bahwa utas yang memeriksanya akan melihatnya telah disetel saat berikutnya memeriksa tanpa harus menggunakansynchronized
blok.sumber
Variabel yang dideklarasikan dengan
volatile
kata kunci, memiliki dua kualitas utama yang membuatnya istimewa.Jika kita memiliki variabel volatil, itu tidak bisa di-cache ke memori cache (mikroprosesor) komputer dengan utas apa pun. Akses selalu terjadi dari memori utama.
Jika ada operasi tulis yang sedang berjalan pada variabel yang tidak stabil, dan tiba-tiba operasi baca diminta, dijamin operasi penulisan akan selesai sebelum operasi baca .
Dua kualitas di atas menyimpulkan itu
Dan di sisi lain,
volatile
kata kunci adalah cara yang ideal untuk mempertahankan variabel bersama yang memiliki 'n' jumlah utas pembaca dan hanya satu utas penulis untuk mengaksesnya. Setelah kami menambahkanvolatile
kata kunci, itu selesai. Tidak ada overhead lain tentang keamanan ulir.Sebaliknya
Kami tidak dapat menggunakan
volatile
kata kunci semata-mata, untuk memenuhi variabel bersama yang memiliki lebih dari satu penulis yang mengaksesnya .sumber
Tidak ada yang menyebutkan perlakuan operasi baca dan tulis untuk tipe variabel panjang dan ganda. Baca dan tulis adalah operasi atom untuk variabel referensi dan untuk sebagian besar variabel primitif, kecuali untuk tipe variabel panjang dan ganda, yang harus menggunakan kata kunci yang mudah menguap untuk menjadi operasi atom. @tautan
sumber
Ya, volatile harus digunakan kapan pun Anda ingin variabel yang dapat diubah diakses oleh banyak utas. Ini bukan penggunaan umum yang sangat umum karena biasanya Anda perlu melakukan lebih dari satu operasi atom (misalnya memeriksa keadaan variabel sebelum memodifikasinya), dalam hal ini Anda akan menggunakan blok yang disinkronkan sebagai gantinya.
sumber
Menurut pendapat saya, dua skenario penting selain menghentikan utas yang digunakan kata kunci yang mudah menguap adalah:
sumber
Anda harus menggunakan kata kunci 'mudah menguap', atau 'disinkronkan' dan alat serta teknik kontrol konkurensi lain yang mungkin Anda miliki jika Anda mengembangkan aplikasi multithreaded. Contoh aplikasi tersebut adalah aplikasi desktop.
Jika Anda mengembangkan aplikasi yang akan digunakan untuk server aplikasi (Tomcat, JBoss AS, Glassfish, dll) Anda tidak perlu menangani kontrol konkurensi sendiri karena sudah ditangani oleh server aplikasi. Bahkan, jika saya ingat dengan benar standar Java EE melarang kontrol konkurensi dalam servlets dan EJB, karena itu adalah bagian dari lapisan 'infrastruktur' yang seharusnya Anda bebas dari penanganannya. Anda hanya melakukan kontrol konkurensi dalam aplikasi tersebut jika Anda menerapkan objek tunggal. Ini bahkan sudah diatasi jika Anda merajut komponen Anda menggunakan frameworkd seperti Spring.
Jadi, dalam kebanyakan kasus pengembangan Java di mana aplikasi adalah aplikasi web dan menggunakan kerangka kerja IoC seperti Spring atau EJB, Anda tidak perlu menggunakan 'volatile'.
sumber
volatile
hanya menjamin bahwa semua utas, bahkan sendiri, bertambah. Sebagai contoh: penghitung melihat wajah variabel yang sama pada saat yang sama. Itu tidak digunakan bukannya disinkronkan atau atom atau hal-hal lain, itu benar-benar membuat pembacaan disinkronkan. Tolong jangan membandingkannya dengan kata kunci java lainnya. Seperti contoh yang ditunjukkan di bawah ini, operasi variabel yang tidak tetap juga bersifat atomis, mereka gagal atau berhasil sekaligus.Bahkan Anda menempatkan volatile atau tidak, hasilnya akan selalu berbeda. Tetapi jika Anda menggunakan AtomicInteger seperti di bawah ini hasilnya akan selalu sama. Ini sama dengan disinkronkan juga.
sumber
Ya, saya menggunakannya cukup banyak - ini bisa sangat berguna untuk kode multi-threaded. Artikel yang Anda tunjuk adalah yang bagus. Padahal ada dua hal penting yang harus diingat:
sumber
Setiap utas yang mengakses bidang volatil akan membaca nilai saat ini sebelum melanjutkan, alih-alih (berpotensi) menggunakan nilai yang di-cache.
Hanya variabel anggota yang dapat berubah-ubah atau sementara.
sumber
Pastinya ya. (Dan tidak hanya di Jawa, tetapi juga di C #.) Ada kalanya Anda perlu mendapatkan atau menetapkan nilai yang dijamin menjadi operasi atom pada platform Anda, int atau boolean, misalnya, tetapi tidak memerlukan overhead dari penguncian utas. Kata kunci yang mudah menguap memungkinkan Anda untuk memastikan bahwa ketika Anda membaca nilai bahwa Anda mendapatkan nilai saat ini dan bukan nilai yang di-cache yang baru saja dibuat usang oleh tulisan di utas lainnya.
sumber
Ada dua penggunaan kata kunci volatile yang berbeda.
Sebuah bendera sibuk digunakan untuk mencegah thread dari melanjutkan saat perangkat sedang sibuk dan bendera tidak dilindungi oleh kunci:
Utas pengujian akan dilanjutkan ketika utas lain mematikan bendera sibuk :
Namun, karena sibuk sering diakses di utas pengujian, JVM dapat mengoptimalkan tes dengan menempatkan nilai sibuk dalam register, kemudian menguji konten register tanpa membaca nilai sibuk dalam memori sebelum setiap tes. Utas pengujian tidak akan pernah melihat perubahan yang sibuk dan utas lainnya hanya akan mengubah nilai sibuk di memori, menghasilkan jalan buntu. Mendeklarasikan flag sibuk sebagai volatile memaksa nilainya untuk dibaca sebelum setiap tes.
Menggunakan variabel volatile mengurangi risiko kesalahan konsistensi memori , karena setiap penulisan ke variabel volatile membentuk hubungan "terjadi sebelum" dengan pembacaan selanjutnya dari variabel yang sama. Ini berarti bahwa perubahan ke variabel volatil selalu terlihat oleh utas lainnya.
Teknik membaca, menulis tanpa kesalahan konsistensi memori disebut aksi atom .
Tindakan atom adalah tindakan yang secara efektif terjadi sekaligus. Tindakan atom tidak bisa berhenti di tengah: itu bisa terjadi sepenuhnya, atau tidak terjadi sama sekali. Tidak ada efek samping dari aksi atom yang terlihat sampai aksi selesai.
Di bawah ini adalah tindakan yang dapat Anda tentukan yang bersifat atom:
Bersulang!
sumber
volatile
mengatakan untuk seorang programmer bahwa nilainya selalu up to date. Masalahnya adalah bahwa nilainya dapat disimpan pada berbagai jenis memori perangkat keras. Misalnya bisa register CPU, cache CPU, RAM ... register СPU dan cache CPU milik CPU dan tidak dapat berbagi data tidak seperti RAM yang ada di penyelamatan dalam multithreading envirompmentvolatile
kata kunci mengatakan bahwa suatu variabel akan dibaca dan ditulis dari / ke memori RAM secara langsung . Ini memiliki beberapa jejak perhitunganJava 5
diperpanjangvolatile
dengan mendukunghappens-before
[Tentang]volatile
kata kunci tidak menyembuhkan suaturace condition
situasi ketika beberapa thread dapat menulis beberapa nilai secara bersamaan. Jawabannya adalahsynchronized
kata kunci [Tentang]Akibatnya itu aman hanya ketika satu utas menulis dan lain-lain hanya membaca
volatile
nilaivolatile vs disinkronkan
sumber
Volatile mengikuti.
1> Baca dan tulis variabel volatil dengan utas berbeda selalu dari memori, bukan dari cache utas atau cpu register. Jadi setiap utas selalu berurusan dengan nilai terbaru. 2> Ketika 2 utas berbeda bekerja dengan instance atau variabel statis yang sama di heap, orang mungkin melihat tindakan orang lain tidak sesuai pesanan. Lihat blog jeremy manson di ini. Tetapi volatile membantu di sini.
Mengikuti kode yang berjalan sepenuhnya menunjukkan bagaimana sejumlah utas dapat mengeksekusi dalam urutan yang telah ditentukan dan mencetak hasil tanpa menggunakan kata kunci yang disinkronkan.
Untuk mencapai ini, kita dapat menggunakan kode berjalan lengkap berikut ini.
Tautan github berikut memiliki readme, yang memberikan penjelasan yang tepat. https://github.com/sankar4git/volatile_thread_ordering
sumber
Dari halaman dokumentasi oracle , kebutuhan untuk variabel volatile muncul untuk memperbaiki masalah konsistensi memori:
Ini berarti bahwa perubahan pada suatu
volatile
variabel selalu terlihat oleh utas lainnya. Ini juga berarti bahwa ketika utas membaca variabel yang tidak stabil, ia melihat tidak hanya perubahan terbaru kevolatile
, tetapi juga efek samping dari kode yang menyebabkan perubahan.Seperti yang dijelaskan dalam
Peter Parker
jawaban, tanpa adanyavolatile
pengubah, setiap tumpukan thread dapat memiliki salinan variabel mereka sendiri. Dengan membuat variabel sebagaivolatile
, masalah konsistensi memori telah diperbaiki.Lihat halaman tutorial jenkov untuk pemahaman yang lebih baik.
Lihat pertanyaan SE terkait untuk beberapa detail lebih lanjut tentang volatile & use cases untuk menggunakan volatile:
Perbedaan antara volatile dan disinkronkan di Jawa
Satu kasus penggunaan praktis:
Anda memiliki banyak benang, yang perlu untuk mencetak waktu saat ini dalam format tertentu misalnya:
java.text.SimpleDateFormat("HH-mm-ss")
. Yon dapat memiliki satu kelas, yang mengubah waktu saat ini menjadiSimpleDateFormat
dan memperbarui variabel untuk setiap satu detik. Semua utas lainnya dapat menggunakan variabel volatil ini untuk mencetak waktu saat ini dalam file log.sumber
Variabel Volatile adalah sinkronisasi ringan. Ketika visibilitas data terbaru di antara semua utas adalah persyaratan dan atomisitas dapat dikompromikan, dalam situasi seperti itu, Variabel Volatil harus lebih disukai. Baca pada variabel yang mudah menguap selalu mengembalikan penulisan terbaru yang dilakukan oleh utas apa pun karena mereka tidak di-cache dalam register atau dalam cache di mana prosesor lain tidak dapat melihat. Volatile Bebas Kunci. Saya menggunakan volatile, ketika skenario memenuhi kriteria seperti yang disebutkan di atas.
sumber
Tombol volatil saat digunakan dengan variabel, akan memastikan bahwa utas yang membaca variabel ini akan melihat nilai yang sama. Sekarang jika Anda memiliki banyak utas yang membaca dan menulis ke suatu variabel, membuat variabel volatile tidak akan cukup dan data akan rusak. Utas gambar telah membaca nilai yang sama tetapi masing-masing telah melakukan beberapa chages (katakanlah menambahkan penghitung), ketika menulis kembali ke memori, integritas data dilanggar. Itu sebabnya perlu untuk membuat variabel disinkronkan (cara yang berbeda dimungkinkan)
Jika perubahan dilakukan oleh 1 utas dan yang lainnya hanya perlu membaca nilai ini, volatile akan cocok.
sumber
variabel volatile pada dasarnya digunakan untuk pembaruan instan (flush) di baris cache bersama utama setelah diperbarui, sehingga perubahan tercermin ke semua utas pekerja segera.
sumber
Di bawah ini adalah kode yang sangat sederhana untuk menunjukkan persyaratan
volatile
untuk variabel yang digunakan untuk mengontrol eksekusi Thread dari utas lainnya (ini adalah satu skenario di manavolatile
diperlukan).Ketika
volatile
tidak digunakan: Anda tidak akan pernah melihat pesan ' Berhenti di: xxx ' bahkan setelah ' Berhenti di: xxx ', dan program terus berjalan.Saat
volatile
digunakan: Anda akan segera melihat ' Berhenti di: xxx '.Demo: https://repl.it/repls/SilverAgonizingObjectcode
sumber