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

我是否错误使用了synchronized?并发计数结果异常求助

问题原因与解决办法

你的代码里synchronized和ReentrantLock都没失效,问题出在主线程没有等线程池里的任务全部执行完就打印了count,而且错误用了shutdownNow()直接终止任务。

具体问题分析

  • executor.shutdownNow()会立刻终止线程池:它会中断正在运行的任务,还会取消所有未开始执行的任务。这就导致你提交的10000个任务里,很多根本没机会执行,所以count的结果会在3000-8000波动。
  • 主线程提交完任务后直接打印count,此时大部分任务还没跑完,自然拿不到正确的10000。

修正方案

把线程池的关闭逻辑改成先平缓关闭,再等待所有任务执行完毕:

  1. 用executor.shutdown()替代shutdownNow(),这个方法会拒绝新任务,但会等待已提交的任务全部执行完。
  2. 调用executor.awaitTermination()设置超时时间,确保主线程等所有任务跑完再打印结果。

修正后的synchronizedIncrement方法示例:

int count = 0;
public void synchronizedIncrement(){
    ExecutorService executor = Executors.newFixedThreadPool(5);

    IntStream.range(0, 10000)
            .forEach(i -> executor.submit(this::incrementSync));

    executor.shutdown(); // 停止接受新任务,等待已提交任务完成
    try {
        // 等待10秒,确保所有任务执行完毕
        if (!executor.awaitTermination(10, TimeUnit.SECONDS)) {
            // 超时未完成则强制终止
            executor.shutdownNow();
        }
    } catch (InterruptedException e) {
        executor.shutdownNow();
        Thread.currentThread().interrupt();
    }

    System.out.println("Incremented count by: " + count);
}

void incrementSync(){
    synchronized(this) {
        count = count + 1;
    }
}

如果是用increment()方法(ReentrantLock版本),只需要把executor.submit(this::incrementSync)改成executor.submit(this::increment),其他线程池的关闭逻辑一样,就能得到正确的10000。

另外补充:count变量不需要额外加volatile,因为synchronized和ReentrantLock的锁释放操作会保证线程间的可见性,只要锁的逻辑正确,count的值会被正确同步。

内容的提问来源于stack exchange,提问作者Martin Emil Wøbbe

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.16 11:50:20