liuchen’s blog【笔记】深入学习volatile

1、volatile关键字与内存屏障

编译器在编译程序时,会对volatile关键字增加以下内存屏障:
1、在每个volatile写之前增加一个StoreStore屏障。
2、在每个volatile写之后增加一个StoreLoad屏障。
3、在每个volatile读之后增加一个LoadLoad屏障。
4、在每个volatile读之后增加一个LoadStore屏障。

需要注意的是,具体程序在编译过程中只会保留必要的内存屏障,比如在volatile读操作后面没有额外的读操作了,那么在编译之后的指令序列中则不会插入
LoadLoad屏障。

2、volatile关键字内存语义和实现

当写一个volatile变量时,JMM会把该线程对应的本地内存中的所有共享变量刷新到主存。
当读一个volatile变量时,JMM会把该线程对应的本地内存置为无效,从主存读取变量值。

volatile关键字的修饰会禁止某些 编译器级别 和 处理器级别 的重排序
假设有两个连续的操作:
a) 当第二个操作是volatile写的时候,不管第一个操作是什么,都不能进行重排序。原因是:如果进行指令重排,那么前面的操作可能不会被写回到内存。例如:
    int a;
    volatile boolean b;
    a = 1;//
    b = false;//这两句赋值不能被重排,否则a = 1将变成内存不可见的。

b) 当第一个操作是volatile读的时候,不管第二个操作是什么,都不能进行重排序。
    int a;
    volatile boolean b;
    boolean c = b;//
    int d = a;//这两句赋值不能被重排,否则a可能读到线程本地内存的值。

c) 当第一个操作是volatile写,第二个操作是volatile读的时候,不能进行重排序。
    volatile int a;
    volatile boolean b;
    b = false;//
    int c = a;//这两句赋值不能被重排,