【Java高级】volatile变量详解

volatile概念

是java虚拟机提供的轻量级的同步机制

特性

保证可见性

说到volatile的可见性就要先说说JMM模型

JMM内存模型

JMM(Java内存模型)本身是一种抽象的概念,并不真实存在,它描述的是一组规则或规范,通过这组规范定义了程序中的各个变量(包括实例字段,静态字段和构成数组对象的元素)的访问方式。

JMM关于同步的规定:

  • 线程解锁前,必须把共享变量的值刷回主内存
  • 线程加锁前,必须读内存的最新值到自己的工作内存
  • 加锁解锁是同一把锁

JMM特性

  1. 可见性
  2. 原子性
  3. 有序性

验证volatile可见性

资源类

class MyData{
    int number=0;
    public void addTo60(){
        this.number=60;
    }
}

main方法

  public static void main(String[] args){
        MyData myData=new MyData();
        new Thread(()-> {
            System.out.println(Thread.currentThread().getName()+"\t come in");
            // 暂停线程
            try { TimeUnit.SECONDS.sleep(3);}catch (InterruptedException e){e.printStackTrace();}
            myData.addTo60();
            System.out.println((Thread.currentThread().getName()+"\t updated number value:" +myData.number));

        },"A").start();
        // 第2个线程就是我们的main线程
        while(myData.number==0){

        }
        System.out.println(myData.number);
        System.out.println(Thread.currentThread().getName()+"\t mission is over main get number:"+myData.number);
    }

执行结果
【Java高级】volatile变量详解
代码停留在 while(myData.number==0){ },一直没有动

分析:
这是因为,在A线程中虽然修改了number=60,但是由于主内存修改后没有办法通知线程main,所以number此时仍为0

优化
【Java高级】volatile变量详解
结果
【Java高级】volatile变量详解

分析:
明显,main线程收到了A线程修改变量的通知,结果被打印出来

不保证原子性

原子性:不可分割,完整性,也即某个线程正在做某个具体业务时,中间不可以被加塞或者被分隔。需要整体完整,要么同时成功,要么同时失败。

验证volatile不保证原子性

资源类

class MyData{
    volatile int number=0;
    public void addTo60(){
        this.number=60;
    }

    public void addPlus(){
        this.number++;
    }
}

main

public static void main(String[] args){

        MyData myData=new MyData();

        for (int i = 0; i <=20 ; i++) {
            new Thread(()->{
                for (int j=1;j<=1000;j++){
                    myData.addPlus();
                }
            },String.valueOf(i)).start();
        }
        // 需要等待20个线程全部计算完成,再用main线程取得最后结果值
        while (Thread.activeCount()>2){
            Thread.yield();
        }
       System.out.println(Thread.currentThread().getName()+"\t final number value"+myData.number);
    }

执行结果
【Java高级】volatile变量详解

禁止指令重排

为了优化程序性能,编译器和处理器会对java编译后的字节码和机器指令进行重排序

上一篇:docker安装mysql:5.7


下一篇:Docker 安装 Elasticsearch 和 Kibana