VarHandle 提供了 plain、opaque、acquire/release、volatile 四档内存序。它们的差别能直接测出来吗?这篇用 jcstress 做消息传递测试,再用一个会「永远看不到写入」的热循环验证可见性的差别,并且如实说明:顺序重排这一项,这台机器上没有测出来(下一篇 final 字段与安全发布也会用到这些概念)。
JDK 21,jcstress 0.16,default 模式(整个运行 154 秒),Apple Silicon(arm64)
各写法下四种结果(y, x)出现的次数:
普通读写(x = 1; y = 1 / r1 = y; r2 = x) 状态 OK (0, 0) 1,929,905 (0, 1) 19,856 (1, 1) 72,421,329
Opaque(setOpaque / getOpaque) 状态 OK (0, 0) 106,190,005 (0, 1) 28,705 (1, 1) 22,362,416
Release / Acquire(y 用 setRelease / getAcquire) 状态 OK (0, 0) 33,343,067 (0, 1) 10,839 (1, 0) 0 (1, 1) 33,511,265
volatile(x、y 都是 volatile) 状态 OK (0, 0) 93,859,864 (0, 1) 39,958 (1, 0) 0 (1, 1) 71,658,469plain:3 秒后读线程仍然没有看到写线程在 300 ms 时写入的值(循环没有结束) opaque:循环在 304 ms 后结束,看到了写入(空转 多次) acquire:循环在 308 ms 后结束,看到了写入(空转 多次) volatile:循环在 304 ms 后结束,看到了写入(空转 多次)