volatile可替代锁用于单次状态变更+单次感知的轻量通知,依靠可见性与有序性保障;适用布尔/整型标志位单赋值场景,不适用于多次通知、带参传递、清零操作或复合逻辑。

volatile 可以在轻量级消息通知中替代锁,前提是通知逻辑只涉及「单次状态变更 + 单次感知」,不依赖复合操作。它靠的是可见性与有序性保障,而不是互斥控制。
适用场景:状态标志型通知
这是 volatile 最典型、最安全的用法。比如一个线程设置完成信号,另一个线程轮询等待——只要通知只发生一次,且接收方只关心“是否已通知”,就非常适合用 volatile。
- 变量必须是布尔型、整型等基础类型或包装类(如 AtomicBoolean 更推荐,但 volatile boolean 已足够)
- 通知动作只能是单赋值,例如 done = true,不能是 count++ 或 flag = !flag
- 接收方使用简单 while 循环检测,不依赖该变量做计算或二次修改
为什么能替代 synchronized?
因为这类通知不需要“原子地读-改-写”,只需要“写后立即被读到”。volatile 恰好解决两个关键问题:
-
可见性:线程 A 写
notified = true后,线程 B 下一次读notified一定看到 true,不会因本地缓存而卡在 false - 有序性:JVM 和 CPU 不会把对其他变量的读写重排到 volatile 写之前,或重排到 volatile 读之后,保证通知前的准备工作(如数据写入)在线程 B 看来已生效
典型代码模式
以下是一个生产者-消费者风格的轻量通知示例:
Java项目代码review工具。分析Git变更+完整调用链路上下文,推断业务需求,进行多维度评分和分类汇总,生成完整PRD文档。包含细粒度Java代码审查清单(Null安全、异常处理、Streams、并发、equals/hashCode、资源管理、API设计、性能、MyBatis/ORM、事务边界、SQL/DD...
立即学习“Java免费学习笔记(深入)”;
public class SimpleNotifier {
private volatile boolean ready = false;
private String data;
public void produce(String msg) {
this.data = msg; // 准备数据(普通写)
this.ready = true; // volatile 写:作为“完成”信号
}
public String consume() {
while (!ready) { // volatile 读:等待信号
Thread.onSpinWait(); // 提示 CPU 当前是忙等,非必需但更友好
}
return data; // 此时 data 一定已写入(happens-before 保证)
}
}
注意:data 虽未加 volatile,但由于 ready 的 volatile 写与读构成 happens-before 关系,data = msg 对消费线程也是可见的。
不能替代锁的边界情况
一旦通知逻辑变复杂,volatile 就不再安全,必须换用锁或原子类:
- 需要多次通知(如开关切换),volatile 无法防止重复处理或丢失中间状态
- 通知附带参数需原子传递(如带时间戳的事件),volatile 无法保证多个字段间的一致性
- 接收方要“取走并清零”标志(如
if (flag) { flag = false; ... }),这不是原子操作,可能被并发打断 - 涉及计数、累加、条件更新等复合逻辑,必须用 AtomicInteger 或 synchronized

















