You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

happens-before规则如何覆盖单变量的读写及内存可见性问题?

理解happens-before规则:从内存顺序到单变量可见性

一、happens-before与多变量内存重排(Dekker算法示例)

我把happens-before规则看作是处理**内存顺序(memory ordering)以及判断某种内存顺序是否符合程序顺序(program order)**的核心规则。以经典的Dekker算法场景为例:

public class DekkerMemoryReorderingExample {
    private int x;
    private int y;

    public void T1() {
        x = 1;
        int r1 = y;
    }

    public void T2() {
        y = 1;
        int r2 = x;
    }
}

在缺乏同步机制的情况下,完全可能观察到结果 (r1, r2) = (0, 0)。无论底层是指令调度、CPU指令重排还是缓存导致的写入传播延迟,这种现象都属于StoreLoad内存重排,等价于以下执行顺序:

1. r1 = y
2. r2 = x
3. x = 1
4. y = 1

二、单变量场景下的happens-before与可见性问题(不安全计数器示例)

当场景简化到单个变量时,happens-before规则如何作用于内存顺序?我们来看这个不安全计数器的例子:

public class UnsafeCounter {
    
    private int counter = 0;
    
    public synchronized int increment() {
        counter++;
    }

    public int get() {
        return counter;
    }
}

这个计数器存在明显问题:读取counter时没有持有与写入操作相同的锁,因此无法保证读取操作能看到之前所有的写入结果。从内存模型的正式定义来说,increment()中的写入操作与get()中的读取操作之间不存在happens-before关系。

三、从内存模型抽象层面解释单变量可见性问题

虽然这个场景没有多变量关联,但我们依然可以从内存模型的核心抽象规则来拆解:

  • 程序顺序与内存顺序的脱节:对于单个线程来说,increment()中的counter++(本质是读-改-写三步操作)遵循程序顺序,但由于get()未同步,JVM没有义务保证其他线程的读取操作能观察到这个线程的写入顺序。
  • 内存屏障的缺失:synchronized修饰的increment()会在退出时插入必要的内存屏障(比如StoreStore + StoreLoad),确保该线程的写入操作对后续持有同一锁的线程可见。但get()没有进入同步块,也就不会触发对应的LoadLoad/LoadStore屏障,无法强制从主内存刷新最新值,也无法禁止读取操作被重排到写入操作之前(从其他线程的视角看)。
  • 内存重排的可能性:从内存模型的抽象分类来看,这里可能发生的重排包括:
    • StoreLoad重排:其他线程的读取操作(get()中的return counter)可能被重排到当前线程写入counter的操作之前,导致读取到旧值;
    • 读取操作无同步约束时,JVM允许将get()中的读取操作缓存到寄存器或本地缓存中,后续多次调用get()都直接使用缓存值,完全不感知主内存的更新,这本质上是内存模型允许的"读取重排"(逻辑上等价于读取操作被提前并重复执行)。
  • happens-before的核心约束:JMM的happens-before规则明确:只有当两个操作之间存在明确的happens-before链时,才能保证可见性和顺序性。在这个例子中,increment()的写入和get()的读取之间没有通过锁、volatile或其他同步机制建立happens-before关系,因此JMM允许任何符合单线程程序顺序的内存执行顺序,包括读取操作看不到最新写入值的情况。

内容的提问来源于stack exchange,提问作者TwITe

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.20 13:54:52