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

Java多线程并发时计数器结果小于预期值的原因是什么

问题原因

你遇到的是典型的多线程竞态条件问题,既不是JVM调度漏执行了操作,也不是循环逻辑写错,核心原因是你对共享变量counter的累加操作不是原子操作,并发场景下会出现更新丢失。

counter += add在JVM执行时不是单步完成的,会拆成三个独立步骤:

  1. 从主内存读取counter的当前值,拷贝到线程的本地工作缓存
  2. 在本地缓存中对读取到的值做加法运算
  3. 把运算得到的新值写回主内存的counter变量

只要两个线程的这三个步骤出现交叉执行,就会出现更新覆盖,导致计数小于预期:
举个会导致数值低于98000的典型场景:

  • ThreadOne第一次循环,读取到counter=0,准备计算+1000,此时CPU切换到ThreadTwo
  • ThreadTwo第一次循环,也读取到counter=0,计算+1得到1,写回主内存,然后进入sleep
  • CPU切回ThreadOne,它不会重新读取主内存的最新值,而是用之前读到的0计算0+1000=1000,写回主内存

这一轮执行下来,两个线程各做了一次累加,理论上应该是1001,但实际主内存里counter只有1000,ThreadTwo加的1直接被覆盖丢失了。如果这种交叉发生在ThreadOne自己的两次累加之间(比如ThreadOne第一次加1000读到0还没写回,第二次累加又读到0,两次加1000最终只生效一次),一次就会丢失1000的计数,多次碰撞后最终结果自然会低于98000。

你偶尔能得到正确结果,只是因为两个线程每次更新后都sleep 50ms,大部分时候两个线程的更新步骤刚好错开,没有出现交叉,但这个时机完全由JVM线程调度决定,没有任何保障,所以结果无法稳定复现。

修复方案

要解决计数不准的问题,核心是保证共享变量操作的原子性和内存可见性,两种常用改法:

方案1:使用synchronized加锁

给操作共享变量的方法加上synchronized关键字,利用Java内置锁保证同一时间只有一个线程能执行累加、读取操作,从根源上避免步骤交叉:

class Accum {
    private int counter = 0;
    private static Accum a = new Accum();
    private Accum() {}
    public static Accum getAccum() {
        return a;
    }
    // 加锁保证读操作的可见性
    public synchronized int getCount() {
        return counter;
    }
    // 加锁保证累加操作的原子性
    public synchronized void updateCounter(int add) {
        counter += add;
    }
}

方案2:使用原子类

用JUC包下的AtomicInteger替代普通int类型,它基于CAS机制实现了无锁的原子更新,不需要手动加锁,性能更好:

import java.util.concurrent.atomic.AtomicInteger;

class Accum {
    private AtomicInteger counter = new AtomicInteger(0);
    private static Accum a = new Accum();
    private Accum() {}
    public static Accum getAccum() {
        return a;
    }
    public int getCount() {
        return counter.get();
    }
    public void updateCounter(int add) {
        counter.addAndGet(add);
    }
}

补充说明:以上修改只能保证计数最终累加的结果是正确的(总和981000 + 991 = 98099),但无法保证两个线程的打印顺序、打印时的数值完全符合你的预期——因为线程调度是随机的,可能ThreadTwo先跑完循环打印结果,也可能ThreadOne打印的时候ThreadTwo还剩最后几次累加没执行。如果要严格匹配你写的预期输出顺序和数值,还需要通过Thread.join()等机制控制线程的执行、打印时机。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.26 14:48:21