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

为何MutableInteger非线程安全?stale data问题解析与复现

关于MutableInteger线程不安全与Stale Data的问题解答

嘿,我来帮你把《Java并发编程实战》里这个MutableInteger的问题讲清楚~

一、这个场景下的Stale Data到底指什么?

Stale Data(过期数据)在这里的核心意思是:当一个线程修改了MutableInteger的value值后,其他线程可能无法及时看到这个最新修改,仍然读取到旧的、已经过期的数值。

这背后的原因和Java内存模型有关:每个线程都有自己的工作内存,会把共享变量(比如这里的value)缓存一份到自己的工作内存里。而MutableInteger的value字段既没有用volatile修饰(强制线程读写直接操作主内存),也没有任何同步机制(比如synchronized)来保证内存更新的同步。所以线程A修改value后,这个更新只会留在自己的工作内存,不会同步到主内存;线程B读取value时,还是从自己的工作内存里拿旧的副本,自然就读到了stale data。

二、如何复现Stale Data的场景?

我写一段简单的多线程代码,你运行一下就能直观看到现象:

public class MutableIntegerStaleDemo {
    private static MutableInteger mutableInt = new MutableInteger(0);

    public static void main(String[] args) throws InterruptedException {
        // 线程1:持续读取value,尝试获取最新值
        new Thread(() -> {
            int currentValue = mutableInt.getValue();
            while (currentValue < 10) {
                if (mutableInt.getValue() != currentValue) {
                    currentValue = mutableInt.getValue();
                    System.out.println("线程1读到最新值:" + currentValue);
                }
            }
        }).start();

        // 线程2:每隔1秒更新一次value
        new Thread(() -> {
            int currentValue = mutableInt.getValue();
            while (currentValue < 10) {
                mutableInt.setValue(++currentValue);
                System.out.println("线程2已设置值为:" + currentValue);
                try {
                    Thread.sleep(1000); // 留时间让线程1读取
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }).start();

        Thread.sleep(12000); // 等待线程执行完成
    }
}

// 就是书中的MutableInteger类
class MutableInteger {
    private int value;

    public MutableInteger(int value) {
        this.value = value;
    }

    public int getValue() {
        return value;
    }

    public void setValue(int value) {
        this.value = value;
    }
}

运行后你会发现:线程2每隔1秒就会把value加1,但线程1可能完全读不到这些更新,一直停留在初始的0,直到程序结束——这就是stale data导致的典型现象。

三、多线程使用MutableInteger会引发哪些问题?

除了上面的可见性问题(stale data),还会带来这些隐患:

  • 原子性缺失:如果多个线程做复合操作(比如mutableInt.setValue(mutableInt.getValue() + 1)),会出现竞态条件。比如两个线程同时读到value=5,都加1后设置为6,而不是预期的7——因为getValue()和setValue()是两个独立的操作,没有原子性保证。
  • 程序行为不可预测:因为线程间的数据不同步,程序的执行结果会依赖于线程调度的时机,有时候看似正常,有时候出现错误,排查起来非常困难。
  • 数据一致性破坏:如果依赖MutableInteger的数值做业务逻辑判断,比如判断value是否达到阈值来执行某个操作,可能因为读到stale data,导致逻辑迟迟不触发,或者触发时机错误。

内容的提问来源于stack exchange,提问作者Coder-Man

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.27 09:47:28