public class Demo09 { public static boolean flag = true; public static class T1 extends Thread { public T1(String name) { super(name); } @Override public void run() { System.out.println("线程" + this.getName() + " in"); while (flag) { ; } System.out.println("线程" + this.getName() + "停止了"); } } public static void main(String[] args) throws InterruptedException { new T1("t1").start(); //休眠1秒 Thread.sleep(1000); //将flag置为false flag = false; } }
Jalankan kod di atas dan anda akan mendapati bahawa program tidak boleh ditamatkan.
Terdapat gelung dalam kaedah run() benang t1. Bendera digunakan untuk mengawal sama ada utas utama tidur selama 1 saat dan menetapkan bendera itu sebagai palsu t1 akan mengesan bahawa bendera itu palsu, mencetak "Thread t1 dihentikan", mengapa keputusan berbeza daripada apa yang kita jangkakan? Dengan menjalankan kod di atas, kita boleh menilai bahawa bendera yang dilihat dalam t1 sentiasa benar Selepas utas utama menetapkan bendera kepada palsu, ia tidak dilihat dalam utas t1, jadi ia terus bergelung.
Jadi mengapa saya tidak dapat melihat bendera diubah suai oleh utas utama dalam t1?
Untuk menjelaskan perkara ini, kita perlu terlebih dahulu memahami Model Memori Java (JMM) Komunikasi antara benang Java dikawal oleh Model Memori Java (dirujuk sebagai JMM dalam artikel ini). pembolehubah yang dikongsi oleh utas Apabila kelihatan kepada utas lain. Dari sudut pandangan abstrak, JMM mentakrifkan hubungan abstrak antara utas dan ingatan utama: pembolehubah yang dikongsi antara utas disimpan dalam memori utama (memori utama), dan setiap utas mempunyai memori tempatan peribadi (memori tempatan) , salinan perkongsian pembolehubah yang dibaca/ditulis oleh benang disimpan dalam memori tempatan. Memori tempatan ialah konsep abstrak JMM dan tidak benar-benar wujud. Ia meliputi cache, penimbal tulis, daftar, dan pengoptimuman perkakasan dan pengkompil lain. Gambarajah skematik abstrak model memori Java adalah seperti berikut:
Seperti yang dapat dilihat daripada rajah di atas, benang A perlu berkomunikasi dengan benang B dan mesti melalui mengikuti 2 langkah:
1 Mula-mula, utas A menyegarkan pembolehubah kongsi yang dikemas kini dalam memori tempatan A ke memori utama
2 Kemudian, utas B pergi ke memori utama untuk membaca sebelumnya pembolehubah kongsi yang dikemas kini bagi utas A. Pembolehubah kongsi
digambarkan di bawah melalui rajah skematik:
Seperti yang ditunjukkan dalam rajah di atas, memori tempatan A dan B telah berkongsi pembolehubah dalam salinan memori utama x. Andaikan bahawa pada mulanya, nilai x dalam ketiga-tiga ingatan ini semuanya 0. Apabila thread A sedang dilaksanakan, ia menyimpan sementara nilai x yang dikemas kini (dengan mengandaikan nilainya ialah 1) dalam memori tempatannya sendiri A. Apabila utas A dan utas B perlu berkomunikasi, utas A akan menyegarkan semula nilai x yang diubah suai dalam ingatan setempatnya kepada memori utama Pada masa ini, nilai x dalam ingatan utama menjadi 1. Selepas itu, benang B pergi ke ingatan utama untuk membaca nilai x kemas kini benang A. Pada masa ini, nilai x memori tempatan benang B juga menjadi 1. Secara keseluruhan, kedua-dua langkah ini pada asasnya adalah utas A yang menghantar mesej ke utas B, dan proses komunikasi ini mesti melalui memori utama. JMM menyediakan pengaturcara Java dengan jaminan keterlihatan memori dengan mengawal interaksi antara memori utama dan memori tempatan setiap utas.
Setelah memahami JMM, mari kita lihat soalan di awal artikel Mengapa kita tidak dapat melihat nilai bendera yang diubah suai menjadi palsu oleh utas utama dalam utas t1? :
1 .Selepas utas utama mengubah suai bendera, ia tidak menyegarkannya ke memori utama, jadi t1 tidak dapat melihat
2. Benang utama menyegarkan bendera ke memori utama , tetapi t1 sentiasa membaca bendera dalam ingatan kerjanya sendiri Nilai tidak pergi ke memori utama untuk mendapatkan nilai bendera terkini
Untuk dua situasi di atas, adakah terdapat cara untuk menyelesaikannya. ia?
Adakah terdapat kaedah sedemikian: selepas benang mengubah suai salinan dalam memori kerja, ia serta-merta dimuat semula ke memori utama setiap kali pembolehubah yang dikongsi dibaca dalam memori kerja, ia adalah Baca semula dari memori utama dan kemudian salin ke memori kerja.
Java membekalkan kita kaedah sedemikian menggunakan volatile untuk mengubah suai pembolehubah yang dikongsi boleh mencapai kesan di atas membaca, setiap bacaan akan membaca nilai terkini pembolehubah yang dikongsi dari memori utama, dan kemudian menyalinnya ke memori kerja
2. Benang mengubah suai salinan pembolehubah dalam memori kerja Ia akan dipadamkan ke memori utama serta-merta
Mari ubah suai kod sampel pada permulaan:public volatile static boolean flag = true;
线程t1 in 线程t1停止了
Kini program boleh dihentikan seperti biasa. Meruap menyelesaikan masalah keterlihatan pembolehubah yang dikongsi dalam berbilang utas Keterlihatan merujuk kepada sama ada pengubahsuaian pembolehubah yang dikongsi oleh satu utas kelihatan kepada utas lain.
Atas ialah kandungan terperinci Apakah model memori yang tidak menentu dan Java bagi java high concurrency?. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!