Sila lihat kod berikut
public class TestVolatile {
public static void main(String[] args) throws InterruptedException {
ThreadDemo td = new ThreadDemo();
new Thread(td).start();
Thread.sleep(1);
while(true){
if(td.isFlag()){
System.out.println("------------------");
break;
}
}
}
}
class ThreadDemo implements Runnable {
private boolean flag = false;
@Override
public void run() {
try {
Thread.sleep(200);
} catch (InterruptedException e) {
}
flag = true;
System.out.println("flag=" + isFlag());
}
public boolean isFlag() {
return flag;
}
public void setFlag(boolean flag) {
this.flag = flag;
}
}
Letak Thread.sleep(1)
换成Thread.sleep(1000)
就能获取flag
修改后的值,即td.isFlag()
返回true
.
Walaupun saya telah membaca konsep model memori Java, saya tidak tahu bagaimana untuk mentafsir kod ini Siapa yang boleh menerangkannya?
Soalan berkaitan: Apakah memori kerja Java multi-threading?
Anda perlu beritahu saya dahulu apakah kesan jangkaan anda? Tanya soalan dengan jelas
Jangkaan ini tidak disokong oleh piawaian. Tiada apa-apa yang dilakukan dalam kod untuk menjamin bahawa "tulisan subthread berlaku-sebelum utas utama dibaca".
sleep(1000)
Melihat pengubahsuaian kemudian hanyalah satu kebetulan Jika JVM menunggu lebih lama untuk utas utama untuk melihatnya, atau tidak pernah membiarkan utas utama melihatnya, ia tidak melanggar spesifikasi.Program anda sepatutnya ingin menguji kefungsian kata kunci
volatile
. Tetapi "menggantikanThread.sleep(1)
denganThread.sleep(1000)
akan mencapai kesan yang diingini" bukanlah pemahaman yang betul.Pertama sekali, terdapat dua utas dalam atur cara, utas utama (secara sementara dipanggil utas M) dan
Benang baru(td)
(sementara dipanggil utas T).volatile
关键字的功能。但是 “把Thread.sleep(1)
换成Thread.sleep(1000)
就能获得预期效果” 这样做理解上是不对的。首先,程序中总共有两个线程,主线程(暂称 线程M)和
new Thread(td)
(暂称 线程T)。当写
Thread.sleep(1)
的时候,线程M 在 1ms 之后,便开始在while(true)
循环中检查td.isFlag()
的值,但是因为内存可见性的关系,线程M 并不能及时读取 线程T 中 flag 的值,所以此时导致了死循环;当写
Thread.sleep(1000)
的时候,M 在 1000ms 之后,开始在while(true)
循环中检查td.isFlag()
的值;但是 T 在 200ms 的时候,便将 flag 的值设为true
了,所以,M 在 1000ms 之后检测td.isFlag()
的值肯定是返回true
的,那么第一次判断便会返回true
,产生输出并跳出while(true)
循环。为了让 线程M 及时读取到 线程T 中 flag 的值,需要将 flag 使用
volatile
关键字进行修饰:那么每次对 flag 的修改,其他线程都立马可见。关于
volatile
Apabila menulis
Thread.sleep(1)
, thread M mula menyemaktd.isFlag() dalam gelung
, tetapi disebabkan keterlihatan memori, utas M tidak dapat membaca nilai bendera dalam utas T dalam masa, jadi gelung tak terhingga disebabkan pada masa ini 🎜while(true)
selepas 1ms🎜Apabila menulis
Thread.sleep(1000)
, M mula menyemaktd.isFlag()
dalam gelungwhile(true)
selepas 1000ms. code>; tetapi T menetapkan nilai flag kepadatrue
pada 200ms, jadi M mengesantd.isFlag( selepas 1000ms )
mesti mengembalikanbenar
, maka penghakiman pertama akan mengembalikantrue
, menjana output dan melompat keluar daripada gelungwhile(true)
code>. 🎜🎜Untuk thread M membaca nilai flag dalam thread T dalam masa, flag perlu diubah suai dengan kata kunci
volatile
: 🎜 rrreee 🎜Kemudian setiap pengubahsuaian bendera akan kelihatan serta-merta kepada urutan lain. Mengenai penggunaanvolatile
, anda boleh rujuk blog saya: Java Multithreading (6): Penggunaan kata kunci yang tidak menentu 🎜Anda boleh merujuk kepada tiga kod berikut:disegerakkan untuk menyelesaikan masalah ini. Ini bagus untuk kebanyakan senario kerja
Kod pertama adalah sama dengan situasi anda disebabkan masalah keterlihatan berbilang benang, ia mungkin menyebabkan gelung yang tidak terhingga.
Yang kedua ialah menggunakan
synchronized
解决此问题,大多数工作场景用这个好第三个是使用
volatile
Yang ketiga ialah menggunakanvolatile
untuk menyelesaikan masalah ini, tetapi kata kunci ini sahaja menjamin keterlihatan Dalam senario sebenar, hadnya agak besar, jadi gunakannya dengan berhati-hati