synchronized 能替代 volatile 吗
在 java 中,synchronized 可以替代 volatile 实现可见性和原子性,但两者不能互换使用。因为 synchronized 是阻塞式同步,会引发线程上下文切换和调度开销,而 volatile 是非阻塞的轻量级同步机制。如果你的业务逻辑需要保证操作的原子性(如 i++),必须用 synchronized;如果只是简单的状态标记或单例模式的双重检查锁定中的可见性控制,volatile 更合适。

什么场景下 synchronized 比 volatile 更好
当操作涉及“读取-修改-写入”复合动作时,synchronized 是唯一的选择。例如计数器累加、条件判断后执行特定逻辑等,这些操作无法通过 volatile 保证原子性。此时使用 synchronized 块包裹代码,确保同一时刻只有一个线程能执行该段逻辑,从而避免数据竞争。

public class Counter { private int count = 0; public synchronized void increment() { count++; } public synchronized int getCount() { return count; } }
上述代码中,increment() 方法被 synchronized 修饰,保证了 count++ 的原子性。如果换成 volatile,多个线程同时调用 increment() 会导致最终结果小于预期值。
为什么 volatile 不能替代 synchronized
volatile 只能保证变量的可见性和禁止指令重排序,不具备原子性。对于非原子操作,如自增、条件分支后的赋值等,volatile 无法提供保护。此外,volatile 不会引起线程阻塞,因此在高并发场景下性能优于 synchronized,但在需要互斥访问共享资源时,它无能为力。

public class Singleton { private static volatile Singleton instance; public static Singleton getInstance() { if (instance == null) { synchronized (Singleton.class) { if (instance == null) { instance = new Singleton(); } } } return instance; } }
在双重检查锁定模式中,volatile 用于防止指令重排序导致其他线程看到未完全初始化的对象。这里 volatile 负责可见性,synchronized 负责原子性,二者缺一不可。
基于程序中某个输入、条件或结果的具体问题
在上述双重检查锁定示例中,如果去掉 volatile 关键字,会发生什么?答案是:在某些 JVM 实现中,可能会返回一个未完全初始化的 Singleton 实例。这是因为 new Singleton() 分为三步:分配内存、初始化对象、将引用指向内存地址。如果没有 volatile,JVM 可能重排序这三步,导致其他线程在第二步完成前就拿到了引用,从而访问到未初始化的对象。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











