詭異的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變量

發佈了55 篇原創文章 · 獲贊 75 · 訪問量 14萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章