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

多线程访问AtomicInteger递增计数,结果超预期(21-22)问题排查

问题分析与解决方案:AtomicInteger计数超出预期值

问题根源

虽然AtomicInteger的get()和incrementAndGet()都是原子操作,但判断条件counter.getCount() < 20与递增操作counter.increment()的组合不是原子性的,这会导致竞态条件:

  • 多个线程可能同时读取到当前计数为19(均满足<20的条件)
  • 这些线程会依次执行递增操作,最终计数会超过20(比如21或22)

举个具体场景:线程A读取到19,准备执行递增;此时线程B也读取到19,同样进入循环。线程A执行后计数变为20,线程B继续执行递增,计数就变成了21。如果有更多线程同时触发这个情况,数值会更高。

解决方案

要解决这个问题,必须把判断+递增的逻辑变成原子操作,以下是两种可行方案:

方案1:使用CAS(Compare-And-Set)原子操作

利用AtomicInteger的compareAndSet方法,将判断和更新合并为一个原子步骤。修改Counter类,增加一个原子递增的方法:

class Counter {
    private AtomicInteger atomicInteger = new AtomicInteger(0);

    // 仅当当前值小于max时,才执行递增
    public boolean incrementIfLessThan(int max) {
        int current;
        do {
            current = atomicInteger.get();
            if (current >= max) {
                return false; // 已达到最大值,无需递增
            }
        // 尝试CAS更新:如果当前值还是current,就改为current+1
        } while (!atomicInteger.compareAndSet(current, current + 1));
        return true;
    }

    public int getCount() {
        return atomicInteger.get();
    }
}

然后修改线程中的循环逻辑:

while (counter.incrementIfLessThan(20)) {
    // 空循环,直到无法再递增
}

这种方式完全基于原子类的特性,无需显式加锁,性能更优。

方案2:使用同步块保证原子性

通过synchronized关键字,将判断和递增的逻辑包裹在同一个同步块中,确保同一时间只有一个线程能执行这段代码:

class Counter {
    private AtomicInteger atomicInteger = new AtomicInteger(0);

    public synchronized void incrementUntil(int max) {
        while (atomicInteger.get() < max) {
            atomicInteger.incrementAndGet();
        }
    }

    public int getCount() {
        return atomicInteger.get();
    }
}

线程中直接调用该方法即可:

counter.incrementUntil(20);

这种方式实现简单,适合对性能要求不高的场景。

原代码的其他小问题

  1. Threads类的main方法返回类型应为void(Java标准main方法要求),而非int
  2. 最后返回语句中的变量名错误:count.getCount()应改为counter.getCount()

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.13 20:44:59