詭異的volatile
今天看到一個關於線程可見性的問題,發現一個奇怪的現象
如我有以下程序:
public class Littlehow{
private static boolean flag = true;
public static void main(String[] strs){
new Thread(){
public void run(){
//該變量不是volatile修飾
while(flag){
try{
System.out.println(123);
}catch(Exception e){
System.out.println(e.getMessage());
}
}
}
}.start();
try{
TimeUnit.SECONDS.sleep(1);
}catch(Exception e){
e.printStackTrace();
}
new Thread(){
public void run(){
flag = false;
}
}.start();
}
}
執行程序後的預期結果是死循環,結果程序正常退出。
//System.out.println(123);
結果發現如果註釋掉輸出語句,則程序進入死循環,這是爲什麼呢?
查了資料有個大膽的猜測,那就是因爲在輸出語句中出現了對volatile變量的讀或寫,
這時候我將程序改成下面這樣:
public class Littlehow{
private static boolean flag = true;
public static volatile int i = 0;
public static void main(String[] strs){
new Thread(){
public void run(){
while(flag){
try{
i++;
//System.out.println(123);
}catch(Exception e){
System.out.println(e.getMessage());
}
}
}
}.start();
try{
TimeUnit.SECONDS.sleep(1);
}catch(Exception e){
e.printStackTrace();
}
new Thread(){
public void run(){
flag = false;
}
}.start();
}
}
發現程序果然和預期的一樣正常退出了,因爲在程序中我對具有volatile變量的i進行了讀寫,所以cache被刷新,對flag的更改也被第一個線程所見。
public
static int i = 0;
如果將i變量的volatile屬性去掉,程序又進入死循環。
結果就是如果程序中有對volatile變量的讀寫操作,那麼就算線程中訪問的變量不是用volatile修飾的共享變量也將被刷新到cache中,這在jdk1.3以上的版本都適合。
特別的:在不同操作系統版本上的表現形式可能不同,如在mac上的jdk,對volatile變量進行了讀寫,也不會及時刷新cache的非volatile變量
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.