关于volatile的使用

来源:互联网 发布:apache python 编辑:程序博客网 时间:2024/05/11 23:08

一、论点
第一层  保证原子性,针对64位变量的多线程操作能保证一次操作都是64位
第二层  保证了顺序一致性,不参与重排序在新的内存模型下
第三层  保证了可见性(可见性仅仅对于基本变量,如果是引用变量只能保证在赋值引用的那一刻,如果赋值后其他线程操作这个引用的变量对象  还是不能保证可见性)

二、程序说明

1.        保证原子性

publicclass Ano {

    privatestaticlongnum = Long.MAX_VALUE;

    publicstaticvoid main(String[] args) {

        System.out.println(Long.MAX_VALUE);

        System.out.println(Long.MIN_VALUE);

        new Thread(){

            publicvoid run(){

                while(true){

                    long l =num;

                    if(l==Long.MAX_VALUE){

                        num = Long.MIN_VALUE;

                    }else{

                        num = Long.MAX_VALUE;

                    }

                }

            }

        }.start();

        new Thread(){

            publicvoid run(){

                while(true){

                    long l =num;

                    if(l!=Long.MAX_VALUE && l!=Long.MIN_VALUE){

                        System.out.println(l);

                        return;

                    }

                }

            }

        }.start();

    }

 

}  

 

运行结果:

9223372036854775807

-9223372036854775808

-9223372032559808513

结论:为什么会有第三个输出呢?jvm操作内存时jvm是32位时写入数据的时候最小单位是32位,如果jvm是64位,最小操作单位就是64位。在没锁的情况下,一个线程写入64位,是分2次写的,先写高32位  在写低32位,如果刚好第一个线程在写高32位的时候 另外的线程读取这个long值,就会出错,就会读到最新的高32位,和之前老数据的低32位,就是错的的值了。所以就会出现第三个输出值。

这样就不会有问题了:privatestaticvolatilelongnum = Long.MAX_VALUE;

 

2.        保证了顺序一致性,不参与重排序在新的内存模型下

publicclass A {

   

    privatestatic A a;

   

    privateintx = 1;

    privateinty = 2;

    public A(int x,int y){

        this.x = x;

        this.y = y;

    }

   

    publicstatic A getInstance(){

        if(a==null){

            synchronized (A.class) {

                if(a==null){

                    a =new A(3,4);

                }

            }

        }

        returna;

    }

}

结论:第一个线程获取到a对象看到a的x是3,a的y是4, 但是如果刚好第二个线程访问,

在判断if(a==null)的时候,看到的是a不是null就获取了a对象,但是这个a对象可能还在构造,此时获取到a的时候看到的x还是1或者y还是2,这样的值就是过期的值,这就是重排序。

改成privatestaticvolatile Aa;就不会有这个问题了!

3.        保证了可见性

 publicclass A {

    publicstaticvolatilebooleanb = false;

    publicstaticintx = 1;

 

    publicstaticvoid main(String[] args) {

        new Thread() {

            publicvoid run() {

                boolean bb =b;

                if (bb) {

                    System.out.println(x);

                }

            }

        }.start();

 

        x = 2;

        b =true;

    }

}

结论:X的输出值一定是2!但是如果b不是volatile则不一定,因为底层执行的情况是,main线程先把b=true写入到了内存,再把x=2写入内存的,每个线程有一个工作区间  也就是缓存区间,用来缓存数据,假如b=true先从线程缓存同步到主存,此时x=2还没有同步到主存,其他线程看到的x就是1了。加上volatile,则当b=true执行后,就会吧b=true,x=2都从缓存同步到主存中,这样x就肯定是2了。




0 0
原创粉丝点击