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

Java线程安全计数器越界问题:如何修正计数超出上限异常?

关于线程安全计数器超预期计数的问题解答

嘿,我来帮你捋捋这个线程安全计数器的问题~ 你遇到的计数跑到51、52的情况,核心原因是竞态条件——虽然你的printAndIncrement是静态同步方法,但while循环的条件判断和调用这个方法之间,存在一个“时间窗口”,多个线程可能同时通过了currentValue < 目标值的判断,然后排队进入同步方法执行递增,自然就会超过预期数值。

先回答你的核心问题:要不要在while循环外加synchronized?

不建议直接给while循环整个套synchronized,这样会让所有线程串行执行,完全失去多线程的意义。更合理的做法是把条件判断和递增操作合并到同一个同步上下文里,确保判断+递增的逻辑是原子性的。

具体的修复方案

方案1:把条件判断移入同步方法(简单直接)

修改你的printAndIncrement方法,让它先在同步环境里判断条件,只有满足时才执行打印和递增:

public class MyCounter implements Runnable {
    static int currentValue = 0;
    private static final int MAX_COUNT = 50; // 定义目标最大值,更清晰

    private static synchronized void printAndIncrement() {
        if (currentValue < MAX_COUNT) {
            System.out.println(currentValue);
            currentValue++;
        }
    }

    @Override
    public void run() {
        // 循环调用直到计数达标
        while (currentValue < MAX_COUNT) {
            printAndIncrement();
            // 可选:加小休眠避免空转占用CPU
            try {
                Thread.sleep(10);
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
        }
    }
}

这样一来,每个线程进入同步方法时都会先检查条件,确保只有在计数未达标的情况下才执行递增,从根本上避免了多线程同时通过判断的问题。

方案2:用Java并发包的原子类(更优雅高效)

如果不想手动处理同步,可以用java.util.concurrent.atomic.AtomicInteger,它本身就是线程安全的,通过CAS(比较并交换)操作实现原子性的判断和更新,代码会更简洁:

public class MyCounter implements Runnable {
    private static final AtomicInteger currentValue = new AtomicInteger(0);
    private static final int MAX_COUNT = 50;

    @Override
    public void run() {
        int value;
        while ((value = currentValue.get()) < MAX_COUNT) {
            // CAS操作:如果当前值还是value,就更新为value+1
            if (currentValue.compareAndSet(value, value + 1)) {
                System.out.println(value);
            }
            // 可选:加小休眠优化CPU占用
            try {
                Thread.sleep(10);
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
        }
    }
}

这个方案不需要显式加synchronized,利用原子类的特性保证线程安全,同时性能也比显式同步更好。

关于你提到的“双重检查”

你说的双重检查在这个场景下确实不够优雅,而且如果没有正确处理变量的可见性(比如给currentValue加volatile),双重检查本身可能存在逻辑漏洞。相比之下,上面两种方案要么简单可靠,要么更符合Java并发编程的最佳实践,比双重检查更值得推荐。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.25 06:27:39