🟠 volatile

吞佛童子2022年6月20日
  • Java
  • concurrency
大约 4 分钟

🟠 volatile

1. 使用

  • 修饰变量

2. 作用

1) 保证可见性

  • 对一个 volatile 变量的读,总是能看到(任意线程)对这个 volatile 变量最后的写入
  • 遵循 MESI 协议,被 volatile 修饰的变量会不断从主存嗅探 & CAS 无限循环

  1. 写操作:
  • 当写一个 volatile 变量时,JMM 会把该线程对应的本地内存共享变量值刷回主存,其他线程通过嗅探监听,将自己线程该缓存行无效
  1. 读操作:
  • 当读一个 volatile 变量时,本线程若发现本地内存的缓存行无效,会从主内存中读取共享变量

MESI 协议 [缓存一致性协议]

  • M [Modify] 修改
    • 该缓存行有效,数据只存在于当前线程所在的缓存行
  • E [Exclusive] 独占
    • 该缓存行有效,数据只存在于当前线程所在缓存行,数据和主存中的数据一致
  • S [Shared] 共享
    • 该缓存行有效,数据和主存一致,同时存在于多个缓存行
  • I [Invalid] 无效
    • 该缓存行无效

[注:]

  • MESI 只对单个缓存行加锁,而不影响其他缓存行的数据
  • 当 Modify 时,只能有一个线程可以进行操作,其他线程若想对该缓存行的数据进行修改操作,会失败,且该缓存行的状态变更为 Invalid

2) 保证有序性,禁止指令重排

① 指令重排

  1. 普通情况下,源代码会经过以下步骤,并不一定按照原有指令顺序执行
  1. 即使如此,但仍会遵循 as-if-serial & happen-before 原则

② volatile 禁止指令重排原理

  1. 读操作
    • 禁止后面的 普通读写 + volatile 读写 操作重排到它之前
    • 借助内存屏障实现
  1. 写操作
    • 禁止前面的 普通读写 + volatile 读写 操作重排到它之后
    • 禁止后面的 volatile 读写 操作重排到它之后

3. JMM

1) 作用

  • 屏蔽硬件 & 操作系统的差异,不同系统的主存中有 L1, L2, L3 等分级缓存,JMM 保证在所有系统下 Java 程序能达到一致的访问效果

原子性

  • 通过 lock, unlock, load, read, assign, use, store, write 保证原子操作

有序性

  • 借助 synchronized, volatile 等实现

可见性

  • 遵循 happen-before 原则
  • 借助 synchronized, volatile 等实现

4. happen-before

1) 单线程 happen-before 原则

  • 在同一个线程中,书写在前面的操作 happen-before 后面的操作
  • 前面的操作产生的结果必须对后面的操作可见,而不一定前面的操作必须先于后面的操作执行,如果不影响则可能发生指令重排

2) happen-before 的传递性原则

  • 如果 A 操作 happen-before B 操作,B 操作happen-before C 操作,那么 A 操作happen-before C 操作

3) 线程启动的 happen-before 原则

  • 同一个线程的 start() happen-before 此线程的其它方法

4) 线程中断的 happen-before 原则

  • 对线程 interrupt() 的调用 happen-before 被中断线程的检测到中断发送的代码
  • interrupt() 改变的状态必须对后续执行的检测方法可见

5) 线程终结的 happen-before 原则

  • 线程中的所有操作都 happen-before 线程的终止检测

6) 对象创建的 happen-before 原则

  • 一个对象的初始化完成先于它的 finalize() 调用

7) 锁的 happen-before 原则

  • 同一个锁的 unlock() happen-before 该锁的 lock()

8) volatile的 happen-before 原则

  • 对一个 volatile 变量的 操作 happen-before 对此变量的任意操作
  • volatile 变量的写操作的结果对于发生于其后的任何操作的结果都是可见的
  • x86 架构下 volatile 通过 内存屏障缓存一致性协议 实现了变量在多核心之间的一致性
上次编辑于: 2022/10/10 下午8:43:48
贡献者: liuxianzhishou