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

Java普通变量与volatile变量赋值重排序问题及解决方案咨询

问题解答

嘿,这个问题抓得很准——结合JSR-133的重排序规则和你提到的“无法控制的中间代码”,我们可以一步步拆解:

1. m_normal的赋值能否被重排序到m_volatile的赋值之后?

你参考的JSR-133 Cookbook表格里的重排序规则是核心,结合你无法控制中间代码的前提,分两种情况看:

  • 如果中间的...代码没有任何volatile操作:根据规则,普通写和后续的volatile写是禁止重排序的——编译器和处理器不能把volatile写操作提前到普通写之前执行。这种情况下m_normal的赋值一定早于m_volatile的赋值。
  • 如果中间的...代码包含volatile读操作:情况就会变化!规则里明确,普通写和volatile读是允许重排序的,也就是说m_normal的赋值可能被推迟到volatile读之后;而volatile读和后续的volatile写是禁止重排序的,这就会导致m_normal的赋值最终被重排序到m_volatile的赋值之后。此时对其他线程来说,m_volatile的赋值会先可见,而m_normal的赋值还没完成。

2. get()方法是否可能返回null?

答案是完全有可能,尤其是当中间的...代码存在volatile操作时。当另一个线程调用get():

  1. 先读到m_volatile不为null(说明volatile写已经对该线程可见);
  2. 此时m_normal的赋值可能还没完成,或者还没刷新到主内存对该线程可见;
  3. 最终get()返回null。

就算中间代码没有volatile操作,我们也不能依赖这个假设(毕竟你无法控制这部分代码),所以必须按存在风险的情况处理。

3. 最佳解决方案

既然无法控制...处的代码,我们需要让m_normal的赋值和m_volatile的赋值之间建立可靠的happens-before关系,不管中间代码是什么,这里有几个常用的稳妥方案:

方案一:把m_normal也声明为volatile

直接将m_normal定义为volatile变量,利用volatile的内存语义禁止重排序并保证可见性:

private volatile Object m_normal;
private volatile Object m_volatile;

这种方式开销低,实现简单,volatile写的性能损耗在大多数场景下可以忽略。

方案二:使用synchronized同步块

把赋值和读取逻辑都放到同一个synchronized块中,利用锁的原子性和内存可见性保证:

public void change() {
    synchronized (this) {
        m_normal = new Object();
        ... // 无法控制的代码
        m_volatile = new Object();
    }
}

public Object get() {
    synchronized (this) {
        Object v = m_volatile;
        if (v != null) {
            return m_normal;
        }
        return null;
    }
}

synchronized会保证块内操作的原子性,释放锁时会把所有写操作刷新到主内存,其他线程获取锁时会读取最新的主内存值,完全避免重排序问题。缺点是开销比volatile略大,但如果调用频率不高,这是最稳妥的方案。

方案三:用AtomicReference包装m_normal

如果m_normal是复杂对象,可以用AtomicReference来包装,它的set()方法具有volatile写的语义:

private AtomicReference<Object> m_normal = new AtomicReference<>();
private volatile Object m_volatile;

public void change() {
    m_normal.set(new Object());
    ... // 无法控制的代码
    m_volatile = new Object();
}

这种方式既保证了m_normal赋值的volatile语义,又能适配复杂对象的场景。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.19 07:54:15