- 线程的创建前置于(happens bofere)线程的第一个动作。
- 互斥体
m的解锁前置于(happens before)任何 后续(subsequent) 对互斥体m的锁定。 volatile变量v的写入前置于(happens bofere)任何 后续(subsequent) 对变量v的读取。
“后续(subsequent)” 意味着什么?Java 定义了所有锁定、解锁和 volatile 变量访问的行为,给出了整个程序中所有这些操作的总顺序,就像它们发生在某个顺序一致的交错中一样。“后续(subsequent)”指在总顺序中较晚执行。也就是说:锁定、解锁和 volatile 变量的访问的“总顺序”定义了“后续”的含义,“后续”定义了由特定执行创建的“前置于(happens before)”关系,最终“前置于(happens before)”关系定义了该特定执行是否存在数据竞争。如果没有数据竞争,那么执行就会以顺序一致的方式进行。
事实上, volatile 访问必须表现得像在某种总排序一样,意味这在下面 litmus test 中,不能出现 r1=0 和 r2=0 的结果:
Litmus Test: Store Buffering
Can this program see r1 = 0, r2 = 0?
// Thread 1 // Thread 2
x = 1 y = 1
r1 = y r2 = x
On sequentially consistent hardware: no.
On x86 (or other TSO): yes!
On ARM/POWER: yes!
On Java using volatiles: no.
Java 中对 volatile 变量 x 和 y 的读写不能被重新排序:一个线程的写入一定会同步到第二个,紧随着第二个的写入的读取就一定能看到第一个写入。