volatile能安全替代synchronized或ReentrantLock于纯状态翻转场景,因其提供可见性与禁止重排序,无需互斥;但仅适用于无复合操作(如count++)的单变量独立写入,如isReady=true,不适用于flag=!flag等读-改-写非原子操作。

在纯状态翻转场景(比如 isReady = true)中,volatile 能安全替代 synchronized 或 ReentrantLock,核心在于它提供了**可见性 + 禁止重排序**,而无需互斥——只要不涉及复合操作(如 count++),就足够了。
volatile 保证写操作对所有线程立即可见
普通变量写入可能被缓存在线程本地 CPU 缓存或寄存器中,其他线程读不到最新值。volatile 写会强制将值刷新到主内存,读则强制从主内存重新加载。这正好满足“设标志位后,其他线程立刻能感知”的需求。
- 例如:主线程设置
ready = true,工作线程轮询while (!ready) Thread.yield()—— 没有 volatile,工作线程可能永远看不到 true - volatile 不加锁,无上下文切换开销,比 synchronized 快一个数量级
volatile 禁止编译器和 CPU 的指令重排序
JVM 和硬件可能为优化把赋值语句提前或延后,导致逻辑错乱。volatile 写前后的指令不会被重排越过该写操作(写屏障),读之后的指令也不会被重排到该读之前(读屏障)。
- 典型场景:对象初始化后才设标志位
错误(无 volatile):instance = new SomeObject(); // 可能重排:先分配内存、设引用、再调构造器ready = true;
其他线程看到ready == true,但instance尚未完全构造 -
正确(volatile 修饰 ready):确保
ready = true一定发生在instance完全初始化之后
适用边界:仅限“读-改-写”原子性不要求的场景
volatile 不能保证 isRunning = !isRunning 这类读+写组合操作的原子性(可能两个线程同时读到 true,都算出 false,再同时写回)。此时仍需 synchronized 或 AtomicInteger。
立即学习“Java免费学习笔记(深入)”;
- ✅ 安全用法:
isShutdown = true、shouldStop = false、state = STATE_DONE - ❌ 危险用法:
counter++、flag = !flag、list.add(x) - 注意:即使只是布尔翻转,若逻辑上要求“必须只翻一次”,也要考虑用 CAS 或锁,因为 volatile 不防重复写
与 AtomicBoolean 对比:轻量但功能更少
AtomicBoolean 底层也用 volatile + CAS,但它额外支持原子性 toggle(compareAndSet / getAndSet)和内存屏障控制。
- 如果只需要单向置位(如启动/停止信号),volatile 布尔字段更简洁、无对象封装开销
- 如果需要“读取当前值并原子设新值”,或要避免多次重复设置,AtomicBoolean 更合适
- 两者在单纯写入可见性上性能几乎一致,volatile 略省一点内存


















