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

Java未同步方法为何产生一致结果?新手多线程测试咨询

为什么未同步的线程方法会产生一致结果?

嘿,这个问题挺常见的,刚接触线程同步的时候很容易碰到这种“意外”的一致结果😉。咱们来拆解一下背后的原因:

首先得明确,globalCounter++并不是原子操作——它实际包含三个独立步骤:

  • 读取globalCounter的当前值
  • 对读取到的值执行加1操作
  • 将计算后的新值写回globalCounter

理论上,多线程环境下如果没有同步机制,这三个步骤可能被线程调度器打断,导致竞态条件(比如两个线程同时读取到同一个值,各自加1后写回,最终只完成了一次有效的递增)。但你实际运行没出问题,大概率是这几个原因:

1. 循环次数太少,竞态条件没触发

每个线程只执行5次递增,这种低次数下,线程切换刚好没发生在globalCounter++的三个步骤之间的概率很高。你可以试试把循环次数改成10000次,再跑几次,几乎肯定会得到小于15的结果——这时候竞态条件就会显现出来了。

2. 线程执行时序接近串行

可能你的测试环境中,线程调度器刚好让三个线程串行执行:第一个线程跑完5次递增后,第二个才开始,最后第三个执行。这种情况下自然不会有竞态问题,结果就是3*5=15。

你可以在run方法的循环里加个微小的睡眠,强制增加线程切换的概率,比如:

public void run() {
    for (int i = 0; i < 5; i++) {
        try {
            Thread.sleep(1); // 让线程主动让出CPU,增加切换概率
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        SharedValueHolder.increment();
    }
}

再运行几次,应该就能看到不一致的结果了。

3. 额外的小建议:正确的同步方式

如果想保证结果始终正确,有两种常见的解决办法:

  • 给increment方法加synchronized修饰符,把它变成原子操作:
    public static synchronized void increment() {
        globalCounter++;
    }
    
  • 使用Java并发包中的AtomicInteger,它本身就是为原子递增设计的:
    class SharedValueHolder {
        public static AtomicInteger globalCounter = new AtomicInteger(0);
        public static void increment() {
            globalCounter.incrementAndGet();
        }
    }
    

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.26 09:09:14