volatile的特殊规则

当一个变量被定义称volatile之后,它将具备两项特性:

  • 保证此变量对所有线程的可见性,这里的可见性是指当一个线程修改了

    这个变量的值,新值对于其他线程来说是可以立即得知的。而普通变量

    并不能做到这点,普通变量的值在线程间传递均需要通过主内存来完成。

  • 禁止指令重排,普通的变量仅会保证在该方法的执行过程中所有依赖赋值

    结果的地方都能获取到正确的结果,而不能保证变量赋值操作的顺序与程序

    代码中的执行顺序一致。因为在同一个线程的方法执行过程中无法感知到这点,

    这就是Java内存模型中描述的所谓“线程内表现为串行的语义”(Within-Thread As-If-Serial Semantics

实现原理

使用volatile修饰的变量,赋值后会多执行一个lock add1 $0x0,(%esp)操作,

这个操作的作用相当于一个内存屏障(Memory BarrierMemory Fence),指令

重排时不能把后面的指令重排序到内存屏障之前的位置。

lock add1 $0x0,(%esp)ESP寄存器的值加0,显然是一个空操作。作用是将本处理器

的缓存写入内存,该写入工作会引起别的处理器或别的内核无效化(Invalidate)其缓存,

这种操作相当于对缓存中的变量做了一次Java内存模型中所说的storewrite操作。

通过这么个空操作,可以让volatile变量的修改对其他处理器立即可见。

lock add1 $0x0,(%esp)指令把修改同步到内存时,意味着所有之前的操作都已经执行完成,

这样便形成了“指令重排无法越过内存屏障”的效果。