java volatile的一個驗證反例


    網上關於java volatile的資料已經不少了,但搜了好久也沒看到誰用代碼很好地驗證過使不使用volatile的差異。最近自己寫了個測試,意外的看到了兩者的明顯區別,為什么說意外呢,因為根據我的測試,在32位的JVM(以下均指oracle官方的JVM)上是看不出差異的,也就是說32位的JVM上,不會發生因為沒使用volatile而引起的多個線程讀寫公共變量不同步問題(有誤,見末尾的補充),偶然在64位的JVM上跑了下,問題一下出現了。我一直是用32位的JVM做測試,一直把問題的不出現歸結於概率太低,所以沒遇到,以致於我寫了下面這個把這個小概率事件成倍放大的測試,但還是沒看出差異,后來放到64位的JVM上,問題一下就出現了,程序直接不退出了

/**
 * volatile關鍵字的測試
 * @author trytocatch
 * @date 2013-1-7
 */
public class Volatile {
    long time1;//test運行時,使用兩獨立的變量來保存時間,避免因使用同步而對t1,t2造成影響
    long time2;
    volatile boolean boolValue=true;//volatile
    public static void main(String[] args) throws InterruptedException{
        int size=5000;//測試個數
        Volatile vs[]=new Volatile[size];
        long timeSum = 0;
        for(int n=0;n<size;n++)
            (vs[n]=new Volatile()).test();
//        Thread.sleep(1000);
        for(int n=0;n<size;n++){//統計出,所有線程從boolValue變為false到while(boolValue)跳出所花時間的總和
            timeSum+=vs[n].time2 - vs[n].time1;
            System.out.print(n+"\t"+vs[n].time2 +'\t' + vs[n].time1+'\t'+(vs[n].time2 - vs[n].time1)+'\n');
        }
        System.out.println("響應時間總和(毫微秒):"+timeSum);
        long time1,time2;
        time1 = System.nanoTime();
//        Thread.yield();
        time2 = System.nanoTime();
        System.out.println(time2-time1);//順序執行兩條語句的時間間隔,供參考
    }

    public void test() throws InterruptedException{
        Thread t2=new Thread(){
            public void run(){
                while(boolValue)
                    ;
                time2 = System.nanoTime();
            }
        };
        Thread t1=new Thread(){
            public void run(){
                time1 = System.nanoTime();
                boolValue=false;
            }
        };
        t2.start();
        Thread.yield();
        t1.start();
        t1.join();//保證一次只運行一個測試,以此減少其它線程的調度對 t2對boolValue的響應時間 的影響
        t2.join();
    }
}

至於我上面說的,在32位JVM上,不會發生因為沒使用volatile而引起的多個線程讀寫公共變量不同步問題,因為我把測試的size增加到50000也沒出一個問題,而且一放到64位JVM上,問題立馬出現,所以可以斷定是JVM的差異,至於為什么32位的JVM不會出問題,難道是它根本沒做優化?希望JVM高手指點


補充:今天在網上看到個資料,64位jvm只有server模式(server模式會進行更多的優化),32位JVM默認使用client模式,我將32位JVM設置為server模式后,問題同樣出現了,平時不出現,是因為它根本就沒做這方面的優化,所以,“在32位JVM上,不會發生因為沒使用volatile而引起的多個線程讀寫公共變量不同步問題”的說法有誤,只是參數不同而已

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM