我是否错误使用了synchronized?并发计数结果异常求助
问题原因与解决办法
你的代码里synchronized和ReentrantLock都没失效,问题出在主线程没有等线程池里的任务全部执行完就打印了count,而且错误用了shutdownNow()直接终止任务。
具体问题分析
executor.shutdownNow()会立刻终止线程池:它会中断正在运行的任务,还会取消所有未开始执行的任务。这就导致你提交的10000个任务里,很多根本没机会执行,所以count的结果会在3000-8000波动。- 主线程提交完任务后直接打印count,此时大部分任务还没跑完,自然拿不到正确的10000。
修正方案
把线程池的关闭逻辑改成先平缓关闭,再等待所有任务执行完毕:
- 用
executor.shutdown()替代shutdownNow(),这个方法会拒绝新任务,但会等待已提交的任务全部执行完。 - 调用
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
相关产品推荐
相关产品推荐

