目录
从图中可以看出:
- 当第二个操作是volatile写时, 不管第一个操作是什么, 都不能重排序. 这个规则确保volatile写之前的操作不会被编译器重排序到volatile写之后.
- 当第一个操作是volatile读时, 不管第二个操作是什么, 都不能重排序. 这个规则确保volatile读之后的操作不会被编译器重排序到volatile读之前.
- 当第一个操作是volatile写, 第二个操作是volatile读时, 不能重排序.
为了实现volatile的内存语义, 编译器在生成字节码时, 会在指令序列中插入内存屏障来禁止特定类型的处理器重排序. 对于编译器来说, 发现一个最优布置来最小化插入屏障的总数几乎不可能. 为此, JMM采取保守策略. 下面是基于保守策略的JMM内存屏障插入策略.
- 在每个volatile写操作的前面插入一个StoreStore屏障.
- 在每个volatile写操作的后面插入一个StoreLoad屏障.
- 在每个volatile读操作的后面插入一个LoadLoad屏障.
- 在每个volatile读操作的后面插入一个LoadStore屏障.
在旧的内存模型中, 当1和2之间没有数据依赖关系时, 1和2之间就可能被重排序(3和4类似). 其结果就是: 读线程B执行4时, 不一定能看到写线程A在执行1时对共享变量的修改.
因此, 在旧的内存模型中, volatile的写-读没有锁的释放-获所具有的内存语义. 为了提供一种比锁更轻量级的线程之间通信的机制, JSR-133专家组决定增强volatile的内存语义: 严格限制编译器和处理器对volatile变量与普通变量的重排序, 确保volatile的写-读和锁的释放-获取具有相同的内存语义. 从编译器重排序规则和处理器内存屏障插入策略来看, 只要volatile变量与普通变量之间的重排序可能会破坏volatile的内存语义, 这种重排序就会被编译器重排序规则和处理器内存屏障插入策略禁止.
6. 总结
volatile能保证内存可见性正是通过内存屏障来实现的, 并且不同的编译器对内存屏障的支持不同, 但是由于大多数处理器都使用了写缓冲区, 所以大多数处理器都支持StoreLoad屏障.https://www.cnblogs.com/wuqinglong/p/9948584.html
