特点:

  • 可见性
  • 禁止指令重排序
  • 不保证原子性

可见性:

  • 写入 volatile 变量,会直接写入主内存,并让其他线程的工作内存中的变量副本失效
  • 如果线程工作内存中的变量副本失效后,就会重新从主内存读取

禁止指令重排序:

  • 编译器和处理器都可能对指令进行重排,从而导致多线程环境下出现问题
  • volatile 使用内存屏障来防止指令重排序

原理:

内存间交互操作:

  • lock:锁定主内存的指定变量
  • unlock:取消锁定主内存的指定变量
  • read:将指定变量的值从主内存传输到线程的本地内存
  • load:将 read 操作的变量值赋值本地内存变量
  • use:将本地内存中指定变量的值,传递执行引擎。使用变量时使用
  • assign:从执行引擎中接收变量值并赋值本地内存中的变量。变量赋值时使用
  • store:将指定变量从本地内存传输主内存
  • write:将 store 操作的变量赋值主内存的变量

read -> load
store -> write
Java 内存模型只要求上面两对操作内部按顺序执行,但没有保证是连续执行的,即中间可能会插入其他指令。

volatile 的原理:

数据总线


指令重排序

为了提高性能

编译器和处理器对指令重排序:

  • 编译器优化的重排序
    • 不改变单线程程序语义的前提下,编译器可重排语句的执行顺序
  • 指令级并行的重排序
    • 处理器会将多条指令重叠执行。
    • 如果不存在数据依赖处理器可以改变语句对应机器指令的执行顺序
  • 内存系统的重排序
    • 由于处理器使用缓存和读写缓冲区,这使得 load 和 store 操作可能被重排

有同步的时候,就不需要用 volatile 了