特点:
- 可见性
- 禁止指令重排序
- 不保证原子性
可见性:
- 写入 volatile 变量,会直接写入主内存,并让其他线程的工作内存中的变量副本失效
- 如果线程工作内存中的变量副本失效后,就会重新从主内存读取
禁止指令重排序:
- 编译器和处理器都可能对指令进行重排,从而导致多线程环境下出现问题
- volatile 使用内存屏障来防止指令重排序
原理:
内存间交互操作:
- lock:锁定主内存的指定变量
- unlock:取消锁定主内存的指定变量
- read:将指定变量的值从主内存中传输到线程的本地内存中
- load:将 read 操作的变量值赋值给本地内存的变量
- use:将本地内存中指定变量的值,传递给执行引擎。使用变量时使用
- assign:从执行引擎中接收变量值并赋值给本地内存中的变量。变量赋值时使用
- store:将指定变量从本地内存中传输到主内存中
- write:将 store 操作的变量赋值给主内存的变量
read -> load
store -> write
Java 内存模型只要求上面两对操作内部按顺序执行,但没有保证是连续执行的,即中间可能会插入其他指令。
volatile 的原理:
数据总线
指令重排序
为了提高性能
编译器和处理器对指令重排序:
- 编译器优化的重排序
- 在不改变单线程程序语义的前提下,编译器可重排语句的执行顺序
- 指令级并行的重排序
- 处理器会将多条指令重叠执行。
- 如果不存在数据依赖,处理器可以改变语句对应机器指令的执行顺序
- 内存系统的重排序
- 由于处理器使用缓存和读写缓冲区,这使得 load 和 store 操作可能被重排
有同步的时候,就不需要用 volatile 了