网上关于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而引起的多个线程读写公共变量不同步问题”的说法有误,只是参数不同而已

 

posted on 2013-01-07 20:22  trytocatch  阅读(2974)  评论(4编辑  收藏  举报