Java原子类并发疑问:多线程下程序输出为何不符合预期?
为啥你的AtomicInteger程序输出和预想的不一样?
兄弟,你对原子类的核心认知其实没错:AtomicInteger的incrementAndGet()这类原子方法,确实是靠CAS机制保证同一时间只有一个线程能成功执行,所以最终的计数绝对是准确的(比如10个线程跑下来,最大的数字肯定是10)。
那问题出在哪?看你写的代码,你把「原子计数」和「打印结果」拆成了两个独立操作——这俩加起来可不是原子的!
先把你没写完的代码补全,大概是这样对吧:
public class VisitorCounterAtomic { private AtomicInteger visitorCount = new AtomicInteger(0); public void visitAndPrint() { System.out.println("Total Visitors: " + visitorCount.incrementAndGet()); } public static void main(String... args) { ExecutorService service = null; try { service = Executors.newFixedThreadPool(10); VisitorCounterAtomic counter = new VisitorCounterAtomic(); for (int i = 0; i < 10; i++) { service.submit(counter::visitAndPrint); } } finally { if (service != null) service.shutdown(); } } }
举个具体场景你就懂了:
- 线程A先抢到CPU,执行
incrementAndGet()拿到了数字2,但还没来得及调用println; - 这时候线程B抢到CPU,执行
incrementAndGet()拿到数字3,然后直接完成了打印; - 之后线程A才继续执行打印,结果控制台就先出现
Total Visitors: 3,再出现Total Visitors: 2——看起来顺序乱了,但计数本身一点没错。
说白了,原子类只保证「计数」这一步是线程安全的,但不保证「计数+打印」整个流程的原子性。如果想要打印的顺序和计数的顺序完全一致,你得把这俩操作绑在一起,用同步锁包住:
比如给方法加synchronized关键字:
public synchronized void visitAndPrint() { int currentCount = visitorCount.incrementAndGet(); System.out.println("Total Visitors: " + currentCount); }
或者干脆不用AtomicInteger,直接用普通int加同步(效果一样):
private int visitorCount = 0; public synchronized void visitAndPrint() { visitorCount++; System.out.println("Total Visitors: " + visitorCount); }
另外提一嘴:System.out.println()本身是线程安全的(内部有同步块),但这只能保证打印的内容不会乱码,没法保证多个线程的打印顺序和它们执行计数的顺序一致——毕竟“拿数”和“打印”中间没加锁约束嘛。
内容的提问来源于stack exchange,提问作者iamcrypticcoder
相关产品推荐
相关产品推荐

