volatile ialah kata kunci yang agak penting dalam Java Ia digunakan terutamanya untuk mengubah suai pembolehubah yang akan diakses dan diubah suai oleh urutan yang berbeza.
Dan pembolehubah ini hanya boleh menjamin dua ciri, satu adalah untuk memastikan keteraturan, dan satu lagi adalah untuk memastikan keterlihatan.
Jadi apakah keteraturan dan apakah keterlihatan?
Jadi apakah itu keteraturan?
Malah, susunan pelaksanaan program adalah berdasarkan susunan kod, dan penyusunan semula arahan adalah dilarang.
Nampaknya semula jadi, tetapi tidak adalah untuk JVM mengoptimumkan arahan, meningkatkan kecekapan menjalankan program dan meningkatkan keselarian sebanyak mungkin tanpa menjejaskan hasil pelaksanaan program berbenang tunggal.
Walau bagaimanapun, dalam persekitaran 多线程
, susunan beberapa kod berubah, yang mungkin menyebabkan ralat logik.
Dan tidak menentu terkenal kerana ciri ini.
Bagaimanakah tidak menentu memastikan keteraturan?
Ramai rakan berkata bahawa tidak menentu boleh melarang penyusunan semula arahan, yang memastikan program kod akan dilaksanakan dengan ketat mengikut susunan kod. Ini memastikan keteraturan. Operasi pada pembolehubah yang diubah suai oleh tidak menentu akan dilaksanakan dengan ketat mengikut susunan kod Maksudnya, apabila kod dilaksanakan kepada pembolehubah yang diubah suai oleh meruap, kod sebelumnya mesti dilaksanakan, dan kod berikut tidak boleh dilaksanakan. .
Jika penemuduga tidak terus menggali lebih dalam pada masa ini, maka tahniah, soalan ini mungkin telah terjawab, tetapi jika penemuduga terus menggali lebih dalam, mengapa penyusunan semula perintah itu dilarang? ?
Pelaksanaan daripada kod sumber kepada arahan biasanya dibahagikan kepada tiga penyusunan semula, seperti yang ditunjukkan dalam rajah: Seterusnya, kita perlu melihat bagaimana tidak menentu melarang penyusunan semula arahan.
Kami terus menggunakan kod tersebut untuk mengesahkan:
Jika seseorang melihat kod ini, mereka pasti akan mengatakan bahawa hasil kod ini ialah Apa?Sesetengah orang mengatakan ia adalah 2. Ya, jika anda hanya memanggilnya dalam satu utas, hasilnya adalah 2, tetapi jika ia dipanggil dalam beberapa utas, hasil keluaran akhir tidak semestinya 2 yang kita bayangkan . Ini Apabila melakukan ini, kedua-dua pembolehubah mesti ditetapkan kepada tidak menentu.
Jika anda tahu lebih lanjut tentang mod singleton, anda pasti telah memberi perhatian kepada yang tidak menentu ini.public class ReSortDemo { int a = 0; boolean flag = false; public void mehtod1(){ a = 1; flag = true; } public void method2(){ if(flag){ a = a +1; System.out.println("最后的值: "+a); } } }Lihat kod berikut:
Adakah anda biasa dengan corak singleton di atas?
Ya, ini adalah **pemeriksaan berganda (gaya malas DCL) **class Singleton { // 不是一个原子性操作 //private static Singleton instance; //改进,Volatile 可以保持可见性,不能保证原子性,由于内存屏障,可以保证避免指令重排的现象产生! private static volatile Singleton instance; // 构造器私有化 private Singleton() { } // 提供一个静态的公有方法,加入双重检查代码,解决线程安全问题, 同时解决懒加载问题,同时保证了效率, 推荐使用 public static Singleton getInstance() { if (instance == null) { synchronized (Singleton.class) { if (instance == null) { instance = new Singleton(); } } } return instance; } }
Sesetengah orang akan mengatakan bahawa kerana kewujudan penyusunan semula arahan, mekanisme pengambilan dua hujung tidak tidak berfungsi juga. Ia mesti selamat untuk benang, betul, jadi kata kunci yang disegerakkan digunakan untuk menjadikannya selamat untuk benang. Keterlihatan
Malah, keterlihatan ialah isu sama ada pengubahsuaian kepada pembolehubah yang dikongsi dapat dilihat dengan serta-merta kepada urutan lain dalam persekitaran berbilang benang.
Jadi, di manakah keterlihatan beliau secara umumnya muncul? Di mana ia digunakan?
Hasil larian pastinya:
public class Test { private static boolean flag = false; public static void main(String[] args) throws Exception{ new Thread(new Runnable() { @Override public void run() { System.out.println("线程A开始执行:"); for (;;){ if (flag){ System.out.println("跳出循环"); break; } } } }).start(); Thread.sleep(100); new Thread(new Runnable() { @Override public void run() { System.out.println("线程B开始执行"); flag = true; System.out.println("标识已经变更"); } }).start(); } }Thread A mula dilaksanakan:
Thread B mula dilaksanakanLogo telah berubah
Memang itu sahaja .Bagaimana jika kita menggunakan volatile, maka hasil pelaksanaan kod ini akan berbeza?
Mari cuba:
Dengan cara ini kita boleh melihat hasil pelaksanaan lain, dan pernyataan output dalam gelung boleh dilaksanakan.public class Test { private static volatile boolean flag = false; public static void main(String[] args) throws Exception{ new Thread(new Runnable() { @Override public void run() { System.out.println("线程A开始执行:"); for (;;){ if (flag){ System.out.println("跳出循环"); break; } } } }).start(); Thread.sleep(100); new Thread(new Runnable() { @Override public void run() { System.out.println("线程B开始执行"); flag = true; System.out.println("标识已经变更"); } }).start(); }Dengan kata lain, dalam utas B, kami mengubah suai pembolehubah yang diubah suai ini, kemudian pada akhirnya, dalam utas A, kami boleh membaca Maklumat data kami dengan jayanya. Bolehkah atomicity dijamin?
Tidak, mari kita lihat beberapa kod, pembolehubah diubah suai oleh volatile,
public class Test { // volatile不保证原子性 // 原子性:保证数据一致性、完整性 volatile int number = 0; public void addPlusPlus() { number++; } public static void main(String[] args) { Test volatileAtomDemo = new Test(); for (int j = 0; j < 20; j++) { new Thread(() -> { for (int i = 0; i < 1000; i++) { volatileAtomDemo.addPlusPlus(); } }, String.valueOf(j)).start(); }// 后台默认两个线程:一个是main线程,一个是gc线程 while (Thread.activeCount() > 2) { Thread.yield(); } // 如果volatile保证原子性的话,最终的结果应该是20000 // 但是每次程序执行结果都不等于20000 System.out.println(Thread.currentThread().getName() + " final number result = " + volatileAtomDemo.number); } }hasil nombor akhir utama = 17114
hasil nombor akhir utama = 20000hasil nombor akhir utama = 19317
Tiga hukuman mati, semuanya dengan keputusan yang berbeza
Mengapa ini berlaku? Ini ada kaitan dengan nombor++nombor++ dibahagikan kepada 3 arahan
Laksanakan GETFIELD untuk mendapatkan nombor nilai asal dalam ingatan utama
Laksanakan IADD untuk menambah 1 operasi
Laksanakan PUTFIELD dan tulis nilai dalam memori kerja kembali ke memori utama
Apabila berbilang benang melaksanakan arahan PUTFIELD secara serentak, Terdapat akan menjadi masalah menulis kembali ke ingatan utama, jadi keputusan akhir tidak akan menjadi 20000, jadi tidak menentu tidak dapat menjamin atomicity.
Atas ialah kandungan terperinci Adakah kata kunci Volatile dalam Java menjamin keselamatan benang?. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!