Kata Pengantar:
Terdapat banyak cara untuk melaksanakan mod tunggal, seperti mod lapar, mod malas, kelas dalaman statik dan penghitungan, dsb., apabila penemuduga bertanya "Mengapa mesti tidak menentu ditambah kepada mod tunggal?", maka dia merujuk kepada mengapa pembolehubah persendirian dalam mod malas perlu tidak menentu?
Mod malas merujuk kepada kaedah pemuatan malas bagi penciptaan objek Objek tidak dicipta apabila atur cara bermula, tetapi dicipta hanya apabila ia benar-benar digunakan untuk kali pertama.
Adakah anda ingin menjelaskan mengapa anda perlu menambah tidak menentu? Mari kita lihat kod pelaksanaan khusus mod malas:
public class Singleton { // 1.防止外部直接 new 对象破坏单例模式 private Singleton() {} // 2.通过私有变量保存单例对象【添加了 volatile 修饰】 private static volatile Singleton instance = null; // 3.提供公共获取单例对象的方法 public static Singleton getInstance() { if (instance == null) { // 第 1 次效验 synchronized (Singleton.class) { if (instance == null) { // 第 2 次效验 instance = new Singleton(); } } } return instance; } }
Seperti yang dapat dilihat dari kod di atas, untuk memastikan keselamatan benang dan prestasi tinggi, jika dan disegerakkan digunakan dua kali dalam kod untuk memastikan bahawa pelaksanaan program. Oleh itu, kerana sudah ada disegerakkan untuk memastikan keselamatan benang, mengapa kita perlu menambah tidak menentu pada pembolehubah? Sebelum menjelaskan masalah ini, kita mesti terlebih dahulu memahami pengetahuan prasyarat: Apakah kegunaan volatile?
meruap mempunyai dua fungsi utama, pertama, ia menyelesaikan masalah keterlihatan memori, dan kedua, ia menghalang penyusunan semula arahan.
Masalah keterlihatan memori yang dipanggil merujuk kepada apabila berbilang benang mengendalikan pembolehubah pada masa yang sama Selepas satu utas mengubah nilai pembolehubah, yang lain benang Pengubahsuaian pembolehubah tidak dapat dilihat, yang merupakan masalah keterlihatan memori. Menggunakan volatile boleh menyelesaikan masalah keterlihatan memori , sebagai contoh, kod berikut, apabila tidak menentu tidak ditambah, pelaksanaannya adalah seperti berikut:
private static boolean flag = false; public static void main(String[] args) { Thread t1 = new Thread(new Runnable() { @Override public void run() { // 如果 flag 变量为 true 就终止执行 while (!flag) { } System.out.println("终止执行"); } }); t1.start(); // 1s 之后将 flag 变量的值修改为 true Thread t2 = new Thread(new Runnable() { @Override public void run() { try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("设置 flag 变量的值为 true!"); flag = true; } }); t2.start(); }
The program di atas Keputusan pelaksanaan adalah seperti berikut:
Walau bagaimanapun, selepas program di atas telah dilaksanakan selama N kali, ia masih belum berakhir benang 2 mengubah suai pembolehubah bendera, utas 1 Pengubahsuaian pembolehubah tidak dilihat sama sekali.
Kemudian seterusnya, kami cuba menambah tidak menentu pada bendera Kod pelaksanaan adalah seperti berikut:
public class volatileTest { private static volatile boolean flag = false; public static void main(String[] args) { Thread t1 = new Thread(new Runnable() { @Override public void run() { // 如果 flag 变量为 true 就终止执行 while (!flag) { } System.out.println("终止执行"); } }); t1.start(); // 1s 之后将 flag 变量的值修改为 true Thread t2 = new Thread(new Runnable() { @Override public void run() { try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("设置 flag 变量的值为 true!"); flag = true; } }); t2.start(); } }
Hasil pelaksanaan program di atas. adalah seperti berikut:
Daripada keputusan pelaksanaan di atas, kita dapat melihat bahawa menggunakan volatile boleh menyelesaikan masalah keterlihatan memori dalam program.
Penyusunan semula arahan bermakna semasa pelaksanaan atur cara, pengkompil atau JVM sering menyusun semula arahan untuk meningkatkan prestasi pelaksanaan atur cara. Niat reka bentuk asal bagi penyusunan semula arahan sememangnya sangat baik, dan ia juga boleh memainkan peranan yang besar dalam satu utas Walau bagaimanapun, dalam berbilang benang, menggunakan penyusunan semula arahan boleh menyebabkan isu keselamatan benang.
Masalah keselamatan benang yang dipanggil bermakna hasil pelaksanaan program tidak selaras dengan jangkaan kami. Sebagai contoh, jika hasil yang betul yang kami jangkakan ialah 0, tetapi hasil pelaksanaan program ialah 1, maka ini adalah isu keselamatan rangkaian.
Menggunakan meruap boleh melarang penyusunan semula arahan, dengan itu memastikan program boleh dilaksanakan dengan betul apabila berjalan dalam berbilang rangkaian.
Kembali kepada topik, kami menggunakan tidak menentu dalam mod tunggal, terutamanya kerana meruap boleh melarang penyusunan semula arahan, dengan itu memastikan operasi normal program . Sesetengah pembaca mungkin bertanya soalan di sini, bukankah disegerakkan sudah digunakan untuk memastikan keselamatan benang? Jadi mengapa menambah tidak menentu? Lihat kod di bawah:
public class Singleton { private Singleton() {} // 使用 volatile 禁止指令重排序 private static volatile Singleton instance = null; public static Singleton getInstance() { if (instance == null) { // ① synchronized (Singleton.class) { if (instance == null) { instance = new Singleton(); // ② } } } return instance; } }
Perhatikan kod di atas saya menandakan dua baris kod pada ① dan ②. Menambah tidak menentu pada pembolehubah persendirian adalah terutamanya untuk menghalang penyusunan semula arahan semasa pelaksanaan ②, iaitu, pelaksanaan "instance = new Singleton()" ini objek, tetapi ia Pelaksanaan sebenar dibahagikan kepada 3 langkah berikut:
Buat ruang memori.
Mulakan objek Singleton dalam ruang ingatan.
Tetapkan alamat memori kepada objek contoh (selepas melaksanakan langkah ini, contoh tidak akan sama dengan nol).
jika tidak menentu tidak ditambah, maka benang 1 boleh melakukan penyusunan semula arahan apabila melaksanakan ② kod di atas, menukar susunan pelaksanaan asal bagi 1, 2, dan 3 disusun semula kepada 1, 3, dan 2. Tetapi dalam keadaan istimewa, selepas utas 1 telah melaksanakan langkah 3, jika utas 2 datang dan melaksanakan langkah pertama kod di atas, ia dinilai bahawa objek contoh tidak batal, tetapi utas 1 belum selesai membuat instantiat objek Kemudian Thread 2 akan mendapat objek "separuh" yang dijadikan instantiated, menyebabkan ralat pelaksanaan program Inilah sebabnya mengapa tidak menentu ditambahkan pada pembolehubah persendirian.
Atas ialah kandungan terperinci Mengapakah kata kunci yang tidak menentu perlu ditambahkan pada mod tunggal Java?. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!