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

Java多线程中AtomicBoolean与Boolean的同步差异问题

线程交替打印中三种同步变量的差异解析

1. AtomicBoolean 为什么能正常运行

AtomicBoolean是Java并发包提供的原子类,它的所有读写操作(比如get()、set()、getAndSet())都是原子性的,而且天然保证了变量的可见性。即使你用synchronized包裹业务逻辑,AtomicBoolean的原子操作加上同步块的互斥,完全避免了竞态条件。两个线程每次读取和修改isOddTurn时,都能拿到最新的正确值,自然能交替执行打印逻辑。

2. volatile Boolean作为参数传递时卡住的核心原因

问题出在Boolean是不可变类,以及Java的参数传递规则上:

  • 当你把Boolean作为参数传递给Runnable实现类时,传递的是引用的副本。
  • 当你执行isOddTurn = !isOddTurn时,因为Boolean不可变,实际上是创建了一个新的Boolean对象(比如从Boolean.TRUE变成Boolean.FALSE),原来的引用指向的对象根本没变。
  • 这就导致两个线程持有的是不同的Boolean对象引用:线程A修改的是自己手里的引用指向,线程B始终拿着最初的那个引用,根本感知不到线程A的修改。即使加了volatile,volatile修饰的是原来的变量,但线程B看不到新的引用对象,会一直等待isOddTurn变为预期值,最终程序卡住。

3. volatile Boolean设为全局变量时正常运行的原因

全局变量的情况下,两个线程共享同一个变量引用:

  • 虽然Boolean不可变,但修改时是让全局变量指向新的Boolean对象。
  • volatile关键字保证了这个引用的可见性:一个线程修改了全局变量的引用指向后,另一个线程能立即看到这个新的引用。
  • 再加上synchronized块的互斥,线程每次进入同步块都会读取最新的volatile变量值,能正确判断自己是否该执行打印,所以程序能正常交替输出。

关键总结

synchronized保证的是块内代码的原子性和可见性,但如果变量本身的引用被替换,且线程持有的是旧引用,synchronized也无法解决可见性问题。AtomicBoolean从根本上避免了引用替换的问题(它的内部是用volatile int实现的,修改的是int值而非引用),而全局volatile Boolean则通过共享同一引用让线程能感知到变化,参数传递的volatile Boolean则因为引用副本导致线程各自为政。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.08 22:12:40