volatile保证可见性和禁止指令重排序的原理

下面这段话摘自《深入理解Java虚拟机》:

  “观察加入volatile关键字和没有加入volatile关键字时所生成的汇编代码发现,加入volatile关键字时,会多出一个lock前缀指令”

  lock前缀指令实际上相当于一个内存屏障(也成内存栅栏),内存屏障会提供3个功能:

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

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

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

 

二、内存屏障

1、什么是内存屏障
内存屏障其实就是一个CPU指令,在硬件层面上来说可以扥为两种:Load Barrier 和 Store Barrier即读屏障和写屏障。主要有两个作用:

(1)阻止屏障两侧的指令重排序;

(2)强制把写缓冲区/高速缓存中的脏数据等写回主内存,让缓存中相应的数据失效。

在JVM层面上来说作用与上面的一样,但是种类可以分为四种:


2、volatile如何保证有序性?
首先一个变量被volatile关键字修饰之后有两个作用:

(1)对于写操作:对变量更改完之后,要立刻写回到主存中。

(2)对于读操作:对变量读取的时候,要从主存中读,而不是缓存。

OK,现在针对上面JVM的四种内存屏障,应用到volatile身上。因此volatile也带有了这种效果。其实上面提到的这些内存屏障应用的效果,可以是用happen-before来总结归纳。

3、内存屏障分类
内存屏障有三种类型和一种伪类型:

(1)lfence:即读屏障(Load Barrier),在读指令前插入读屏障,可以让高速缓存中的数据失效,重新从主内存加载数据,以保证读取的是最新的数据。

(2)sfence:即写屏障(Store Barrier),在写指令之后插入写屏障,能让写入缓存的最新数据写回到主内存,以保证写入的数据立刻对其他线程可见。

(3)mfence,即全能屏障,具备ifence和sfence的能力。

(4)Lock前缀:Lock不是一种内存屏障,但是它能完成类似全能型内存屏障的功能。

为什么说Lock是一种伪类型的内存屏障,是因为内存屏障具有happen-before的效果,而Lock在一定程度上保证了先后执行的顺序,因此也叫做伪类型。比如,IO操作的指令,当指令不执行时,就具有了mfence的功能。
 

你可能感兴趣的:(volatile保证可见性和禁止指令重排序的原理)