Banyak teman mungkin pernah mendengar kata kunci yang mudah menguap dan mungkin telah menggunakannya. Sebelum Java 5, itu adalah kata kunci yang kontroversial, karena menggunakannya dalam program sering menghasilkan hasil yang tidak terduga. Hanya setelah Java 5, kata kunci yang mudah menguap mendapatkan kembali vitalitasnya. Meskipun kata kunci yang mudah menguap secara harfiah sederhana untuk dipahami, tidak mudah untuk menggunakannya dengan baik.
1. Pendahuluan
JMM memberikan definisi variabel volatile, final, blok yang disinkronkan untuk memastikan visibilitas.
Untuk variabel yang dimodifikasi dengan volatil, utas akan membaca nilai variabel yang paling dimodifikasi setiap kali menggunakan variabel. Volatile mudah disalahgunakan dan digunakan untuk operasi atom. Saya telah menulis beberapa contoh tes, Anda bisa mencobanya.
2. Program Utama
Kelas Publik Main {public static void main (string [] args) melempar interruptedException {list <tread> threadList = new ArrayList <tread> (); for (int i = 0; i <10; ++ i) {thread thread = Thread baru (runnable baru () {@overridepublic void run () {Single.holder.instance.add ();}}); threadlist.add (thread); thread.start ();} untuk (thread thread: threadlist) thread.join (); System.out.println (single.holder.instance.x);}}3. Tes Mode Singleton
1. Tidak ada volatil, tidak disinkronkan
class tunggal {public int x = 0; public void add () {coba {timeunit.milliseconds.sleep (50);} catch (InterruptedException e) {e.printStackTrace ();} ++ this.x;} public static class pemegang public {public static Single instance = new Single ();}}Hasil output: 8, 9, dan 10 semuanya muncul. Anda dapat menjalankan lebih banyak dan mencoba lebih banyak dan Anda akan menemukan hasil yang berbeda.
2. Ada volatile, tetapi tidak disinkronkan
kelas tunggal {public volatile int x = 0; public void add () {try {timeunit.milliseconds.sleep (50);} catch (interruptedException e) {e.printstacktrace ();} ++ this.x;} pemegang kelas statis public {public static Single single = new Single ();Hasil Output: Jumlah maksimum kejadian adalah 9 dan 10.
3. Tidak volatile, disinkronkan
kelas tunggal {public int x = 0; public disinkronkan void add () {try {timeunit.milliseconds.sleep (50);} catch (interruptedException e) {e.printstacktrace ();} ++ this.x;} public static class pemegang public {public static single single = new Single ();Hasil output: Tidak peduli berapa kali Anda berlari, itu akan menjadi 10.
4. Tentang Aplikasi Volatile di DCL (Kunci Periksa Ganda)
kelas publik lazysingleton {private int somefield; instance private static lazysingleton; private lazysingleton () {this.somefield = new random (). nextInt (200) +1; // (1)} public static lazysingleton getInstance () {if (instance == null) {// (2) disinkronkan (lazysingleton.class) {// (3) if (instance == null) {// (4) instance = new lazysingleton (); // (5)}}} return instance; // (6)} int int getSomefield () {return this.somefield; // (7)}}Pertama -tama, izinkan saya menjelaskan mengapa metode penulisan ini tidak berfungsi di Java!
Misalkan utas I memanggil metode getInstance () untuk pertama kalinya, dan kemudian Thread II juga memanggil metode getInstance () dan metode getomefield (). Yang ingin kami jelaskan adalah bahwa pernyataan Thread I (1) tidak terjadi sebelum Thread II (7). Ketika Thread II mengeksekusi pernyataan (2) dari metode getInstance (), karena akses ke instance tidak ada di blok sinkron, Thread II mungkin atau mungkin tidak mengamati tulisan Thread I untuk contoh dalam pernyataan (5), yaitu, nilai instance mungkin kosong atau tidak kosong. Pertama -tama kami berasumsi bahwa nilai instance tidak kosong, jadi kami mengamati utas itu saya menulis instance. Pada saat ini, Thread II akan menjalankan pernyataan (6) dan secara langsung mengembalikan nilai instance ini, dan kemudian panggil metode getSoMeField () pada instance ini. Metode ini juga dipanggil tanpa sinkronisasi. Oleh karena itu, seluruh operasi Thread II dipanggil tanpa sinkronisasi. Ini menunjukkan bahwa tidak ada hubungan yang terjadi sebelum antara pernyataan (1) Thread I dan pernyataan (7) Thread II. Ini berarti bahwa Thread II mungkin tidak dapat mengamati nilai yang ditulis oleh Thread I kepada Somefiled pada pernyataan (1). Ini adalah masalah dengan DCL. Itu konyol, bukan? DCL awalnya dimaksudkan untuk menghindari sinkronisasi, dan mencapai tujuan ini. Justru karena inilah akhirnya dihukum. Ada bug serius dalam program seperti itu, meskipun probabilitas bug tersebut ditemukan jelas jauh lebih rendah daripada probabilitas memenangkan lotre, dan itu singkat. Yang lebih menakutkan adalah bahwa meskipun itu terjadi, Anda tidak akan berpikir bahwa itu disebabkan oleh DCL.
Pemahaman saya adalah bahwa baik Thread I dan Thread II memiliki penyimpanan kerja sendiri. Setelah utas saya membuat instance, waktu untuk menyegarkan ke memori tidak pasti, jadi sangat mungkin bahwa Thread II tidak dapat mengamati nilai yang ditulis oleh Thread I kepada Somefiled pada pernyataan (1).
Jadi karena ada aturan tambahan yang terjadi sebelum ditambahkan dalam Java 5:
• Tulis operasi ke bidang yang mudah menguap terjadi sebelum operasi baca berikutnya ke bidang yang sama.
Menggunakan aturan ini kita dapat menyatakan contoh sebagai volatile, yaitu: instance lazysingleton statis volatil swasta;
Menurut aturan ini, kita dapat memperoleh pernyataan utas I (5) -> kalimat Thread II (2) (yaitu, utas), sesuai dengan aturan utas tunggal, pernyataan utas I (1) -> kalimat utas I (5) dan kalimat -kalimat II (2) -> Kalimat yang dapat ditulis (7), dan menurut aturan pengiriman, ada pernyataan II (2) -> Kalimat II (7), dan menurut aturan pengiriman, ada pernyataan Thread II (2) -> Kalimat II (7), dan menurut aturan pengiriman, ada pernyataan Thread II (2). Nilai Thread I untuk Somefiled dalam Pernyataan (1), dan program dapat memperoleh perilaku yang benar.
Suplemen: Sebelum Java5, tidak ada perbedaan antara semantik sinkron dari bidang akhir dan variabel lainnya. Di Java5, setelah variabel akhir diatur dalam konstruktor (asalkan referensi ini tidak bocor di konstruktor), utas lain pasti akan melihat nilai -nilai yang ditetapkan dalam konstruktor. Masalah dengan DCL adalah bahwa kita melihat nilai default dari variabel anggota objek, sehingga kita dapat mengatur variabel somefield dari Lazysingleton ke final, sehingga dapat berjalan dengan benar di java5.
Konten di atas adalah pengetahuan kata kunci yang mudah menguap di Java yang diperkenalkan kepada Anda oleh editor. Saya harap ini akan membantu semua orang!