volatile long/double原子读写原理
volatile不就是可见性和禁止重排序嘛有什么难的,结果我听到了volatile能够使long/double的读写变成原子读写,这我就懵了。long/double是64位的对于32位处理器需要两次完成,这就造成32位jvm上long/double读写没有原子性,但是volatile作用不就是禁止重排序和保证可见性怎么会有原子性的能力呢?
解析
volatile通过内存屏障功能获得可见性和禁止重排序就不解析了。直接解析long和double的原子性。
long和double的volatile原子性读写是虚拟机规范中强制要求的。https://docs.oracle.com/javase/specs/jls/se8/html/jls-17.html#jls-17.7
17.7. Non-Atomic Treatment of double and long
For the purposes of the Java programming language memory model, a single write to a non-volatile long or double value is treated as two separate writes: one to each 32-bit half. This can result in a situation where a thread sees the first 32 bits of a 64-bit value from one write, and the second 32 bits from another write.
Writes and reads of volatile long and double values are always atomic.
Writes to and reads of references are always atomic, regardless of whether they are implemented as 32-bit or 64-bit values.
Some implementations may find it convenient to divide a single write action on a 64-bit long or double value into two write actions on adjacent 32-bit values. For efficiency’s sake, this behavior is implementation-specific; an implementation of the Java Virtual Machine is free to perform writes to long and double values atomically or in two parts.
Implementations of the Java Virtual Machine are encouraged to avoid splitting 64-bit values where possible. Programmers are encouraged to declare shared 64-bit values as volatile or synchronize their programs correctly to avoid possible complications.
首先必须使用32位Java虚拟机才能看到非原子操作的效果指定虚拟机参数“-client”,现在64位虚拟机已经将普通long/double读写变成一次操作了。
没有添加volatile

32位Java虚拟机(JIT编译器)执行(动态编译)的效果见上图,可见写long/double是两次操作,普通long/double型变量的读操作使用2条mov指令实现
添加volatile

32位Java虚拟机在x86平台下会使用vmovsd这个原子指令来实现volatile修饰的long/double型变量的读写操作。
总结
所以对于32位虚拟机volatile实现long/double型变量的原子操作是通过优化读写指令将两条指令换成一条指令实现。