为了保证内存可见性,Java 编译器在生成指令序列的适当位置会插入内存屏障指令来禁止特定类型的处理器重排序。JMM 把
内存屏障指令分为下列四类:
屏障类型屏障类型 指令示例指令示例 说明说明
LoadLoad Barriers
Load1; LoadLoad;
Load2
确保 Load1 数据的装载,之前于
Load2 及所有后续装载指令的装载。
StoreStore Barriers
Store1; StoreStore;
Store2
确保 Store1 数据对其他处理器可见
(刷新到内存),之前于 Store2 及所
有后续存储指令的存储。
LoadStore Barriers
Load1; LoadStore;
Store2
确保 Load1 数据装载,之前于 Store2
及所有后续的存储指令刷新到内存。
StoreLoad Barriers
Store1; StoreLoad;
Load2
确保 Store1 数据对其他处理器变得可
见(指刷新到内存),之前于 Load2
及所有后续装载指令的装载。
StoreLoadBarriers 会使该屏障之前的
所有内存访问指令(存储和装载指
令)完成之后,才执行该屏障之后的
内存访问指令。
HAPPENS-BEFORE
JSR-133 内存模型使用 happens-before 的概念来阐述操作之间的内存可见性。在 JMM 中,如果一个操作执行的结果需要对
另一个操作可见,那么这两个操作之间必须要存在 happens-before 关系。这里提到的两个操作既可以是在一个线程之内,也
可以是在不同线程之间。
与程序员密切相关的 happens-before 规则如下:
程序顺序规则:一个线程中的每个操作,happens-before 于该线程中的任意后续操作。
监视器锁规则:对一个监视器的解锁,happens-before 于随后对这个监视器的加锁。
volatile 变量规则:对一个 volatile 域的写,happens-before 于任意后续对这个 volatile 域的读。
传递性:如果 A happens-before B,且 B happens-before C,那么 A happens-before C。
注意,两个操作之间具有 happens-before 关系,并不意味着前一个操作必须要在后一个操作之前执行!happens-before 仅仅
要求前一个操作(执行的结果)对后一个操作可见,且前一个操作按顺序排在第二个操作之前(the first is visible to and
ordered before the second)。
happens-before 与 JMM 的关系如下图所示: