java

java volatile

2018-05-08  本文已影响1人  n油炸小朋友

重排序

在Java内存模型中,为了效率是允许编译器和处理器对指令进行重排序,重排序它不会影响单线程的运行结果,但是对多线程会有影响。

volatile作用

一旦一个共享变量(类的成员变量、类的静态成员变量)被volatile修饰之后,那么就具备了两层语义:

  1. 保证了不同线程对这个变量进行操作时的可见性,即一个线程修改了某个变量的值,这新值对其他线程来说是立即可见的。

  2. 禁止进行指令重排序。

volatile使用条件

volatile相对于synchronized稍微轻量些,因为它不会引起线程上下文的切换和调度。在某些场合它可以替代synchronized,但是又不能完全取代synchronized,只有在某些场合才能够使用volatile。

使用volatile必须满足如下两个条件:

volatile使用场景

volatile经常用于两个场景:状态标记量、double check
double check:

class Singleton{
    private volatile static Singleton instance = null;
     
    private Singleton() {
         
    }
     
    public static Singleton getInstance() {
        if(instance==null) {
            synchronized (Singleton.class) {
                if(instance==null)
                    instance = new Singleton();
            }
        }
        return instance;
    }
}

volatile原理

观察加入volatile关键字和没有加入volatile关键字时所生成的汇编代码发现,加入volatile关键字时,会多出一个lock前缀指令。lock前缀指令其实就相当于一个内存屏障。内存屏障是一组处理指令,用来实现对内存操作的顺序限制。volatile的底层就是通过内存屏障来实现的。

内存屏障会提供3个功能:

  1. 它确保指令重排序时不会把其后面的指令排到内存屏障之前的位置,也不会把前面的指令排到内存屏障的后面;即在执行到内存屏障这句指令时,在它前面的操作已经全部完成;

  2. 它会强制将对缓存的修改操作立即写入主存;

  3. 如果是写操作,它会导致其他CPU中对应的缓存行无效。

原子性:
一个操作或者多个操作 要么全部执行并且执行的过程不会被任何因素打断,要么就都不执行。
volatile是无法保证复合操作的原子性(如自增操作)

可见性:
是指当多个线程访问同一个变量时,一个线程修改了这个变量的值,其他线程能够立即看得到修改的值。
当一个变量被volatile修饰后,表示着线程本地内存无效,当一个线程修改共享变量后他会立即被更新到主内存中,当其他线程读取共享变量时,它会直接从主内存中读取。

有序性:
程序执行的顺序按照代码的先后顺序执行。
Java提供volatile来保证一定的有序性。

上一篇下一篇

猜你喜欢

热点阅读