Volatile
# 变量可见性
每个线程会有各自的线程栈,可以理解为有各自的工作内存,在线程之外还有一个共享的主内存,默认不加 volatile 关键字的变量,JVM 不会保证把变量读取到主内存去。
- 不加 volatile 的变量,读取和更新只影响了当前线程的工作内存,其他线程对变量改变不可见。
- 加了 volatile 的变量,在读取时会先从主内存中加载数据到主内存中。在更新变量时,更新工作内存的同时会去更新主内存(怎么保证一致性的?通过 CPU 的缓存一致性方案解决(MESI),每个线程有自己的存储空间在更新到主存时依赖 CPU 的缓存一致性协议来保证数据一致性)

- 加了 volatile 的变量,在同一线程更新此变量时,会同时把非 volatile 变量刷新到主内存中去。(如果一个线程更新了 volatile 变量 和 非 volatile 变量,另一个线程只更新了非 volatile 变量,怎么保证这个非 volatile 变量的一致性?)
# 指令重排
CPU 为了提高执行效率,会把没有依赖逻辑的变量操作进行指令重排(或者说是执行顺序的不确定性)。(指令重排可能发生在两个环节:1. Java编译阶段,转换为字节码的阶段。2. CPU 执行阶段)
As-if-serial 语义是,所有的动作(Action)都可以为了优化而被重新排序,但是必须保证重新排序后的结果和程序代码本身应有的结果一致。
int a = 1; int b = 2; int c = a + b; // 将上面代码转为字节码或者机器指令,可以展开以下几步 // 1. 对 a 进行赋值 // 2. 对 b 进行赋值 // 3. 取 a 的值 // 4. 取 b 的zhi // 5. 将取到的两个值相加后存入 c在上面的 5 个动作中, 动作 1 可能会和动作 2、4 重排序,动作 2 可能会和动作 1、3 重排序,动作3可能会和动作2、4重排序,动作4可能会和1、3重排序。但动作1和动作3、5不能重排序。动作2和动作4、5不能重排序。因为它们之间存在数据依赖关系,一旦重排,as-if-serial语义便无法保证。
# Happens-Before
# 何时使用 volatile 关键字
# 相关文档
上次更新: 2024/11/05, 03:15:29
← maven命令