• volatile修饰后共享变量具有的特性
  • volatile内存语义是什么以及如何实现
  • [ ] volatile变量和非volatile变量字节码区别

    volatile修饰后共享变量具有的特性

    理解volatile特性的一个好方法是把对volatile变量的单个读/写,看成是使用同一个锁对这些单个读/写操作做了同步

    • 原子性:修饰后的变量的读和写操作都具备原子性
    • 可见性:变量的读总能看到变量之前所有的写操作
    • 禁止重排(书中未提):volatile可以禁止指令重排序

      volatile内存语义是什么以及如何实现

      内存语义是什么

      就是线程A对共享变量的修改会立即刷新到主内存,并把所有本地内存置为无效。

      JMM如何实现volatile的内存语义

      JMM为了实现volatile的内存语义,JMM会限制编译器和处理器的指令重排序。
      总结规则:

    • 第二个操作是volatile写时,第一个操作只要关于这个变量不管是什么都不可以重排序

    • 第一个操作是volatile读时,第二个操作只要关于这个变量不管是什么都不可以重排序
    • 第一操作是volatile写时,且第二个操作是volatile读时,不可重排序

具体实现方式:在生成字节码时,在指令序列中插入内存屏障禁止特定类型处理器重排序
JMM采取的保守策略插入内存屏障,其插入规则:
image.png
image.png
上面是分别在volatile读和写前后,分别要做的操作,但是编译器有可能将不必要的屏障去除,如下图所示:
image.png
除了编译器会优化,不同的CPU也会进行优化,比如X86处理器会将出StoreLoad外的所有屏障都干掉。

volatile变量和非volatile变量字节码区别

大家是不是也很想知道,我加了volatile和不加,具体怎么加屏障?字节码是不一样吗?
这里我看了一篇文章。
加了volatile的变量在字节码层面和非volatile变量字节码并无差别
差别在于字节码生成的汇编码,volatile的变量会多 lock指令,这个指令就相当于屏障

参考资料