volatile仅保证单字段读写屏障,不约束跨变量顺序;memorybarrier提供全局双向屏障,用于修复volatile无法覆盖的重排问题。
volatile 只管自己,MemoryBarrier 管全局顺序
用 volatile 修饰一个字段,只对这个字段的读写插入隐式内存屏障:读是 acquire(后面操作不能上移),写是 release(前面操作不能下移)。但它**不约束其他变量的操作顺序**。比如 _value = 42 和 _ready = true 都是 volatile 字段,编译器和 CPU 仍可能把 _value 赋值重排到 _ready 写入之后——导致另一个线程看到 _ready == true 却读到未初始化的 _value。
-
volatile是字段级语义,不是同步原语,不能建立跨变量的 happens-before 关系 -
Thread.MemoryBarrier()是显式双向屏障,能强制“上面所有内存操作完成后再执行下面所有操作”,适合补足 volatile 的缺口 - 不要指望两个 volatile 字段“自动同步”——它们之间没有顺序保证,必须靠
MemoryBarrier或Interlocked显式串起来
什么时候必须用 MemoryBarrier(),而不是只靠 volatile?
典型场景是“发布-消费”模式中多字段协同:一个线程先写数据、再置标志;另一个线程先查标志、再读数据。仅靠 volatile bool _ready 和 volatile int _value 不够安全。
private volatile bool _ready = false;
private int _value; // 没有 volatile —— 错!或至少没用
<p>// 线程 A
_value = 42;
_ready = true; // volatile 写:release-fence,但只保它自己前面的不往下跑</p><p>// 线程 B
if (_ready) { // volatile 读:acquire-fence,只保它自己后面的不上跑
return _value; // ❌ 可能读到旧值或未定义值
}
正确做法是在读取 _value 前加屏障: