选volatile还是synchronized取决于需求:volatile解决“值能否立刻被看到”,适用于单写多读的状态标志位,不保证原子性;synchronized解决“动作能否被插队”,保证原子性、可见性与有序性,适用于复合操作或多变量协同更新。

选 volatile 还是 synchronized,关键看你要解决的是“值能不能被别人立刻看到”,还是“这一串动作能不能被别人插进来打断”。两者不是轻重搭配,而是分工明确、不能混用。
只读写单个变量,且只需通知状态变化
用 volatile。典型场景是开关类标志位,比如线程控制信号、初始化完成标记、服务启停状态。
- 一个线程负责修改(如 running = false),多个线程只读判断(如 while (running))
- 变量本身不参与计算,也不依赖其他变量——它就是个“信号灯”
- 常见例子:DCL 单例中的 private static volatile Singleton instance,防止 new 指令重排导致未构造完就被其他线程使用
涉及读-改-写,或多个变量需一起更新
必须用 synchronized。volatile 对这类操作完全无效,哪怕变量加了 volatile,i++、list.add(x); size++、账户扣款+日志记录 都会出错。
- 因为这些操作天然包含多步:先读旧值 → 计算新值 → 写回内存,中间可能被其他线程抢占
- synchronized 把整段逻辑锁住,确保“要么全做,要么不做”,同时进出时自动同步内存,可见性自然满足
- 锁粒度尽量小:优先用同步代码块(synchronized(lockObj) { ... }),而不是整个方法
别踩的坑:volatile + synchronized 一起用在同一个变量上
多数情况下是冗余甚至误导。比如:
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
立即学习“Java免费学习笔记(深入)”;
private volatile int counter;
public void increment() {
synchronized (this) {
counter++;
}
}
这里 volatile 完全多余。synchronized 已经保证了进入时读最新值、退出时刷回主内存,JVM 可能直接忽略 volatile 语义。代码反而让人误以为“这个变量特殊”,掩盖了真正该关注的临界区设计问题。
终极判断口诀
问自己三个问题:
- 这个变量是不是只由一个线程写、多个线程读?→ 是,考虑 volatile
- 有没有“读取→计算→写入”这种两步以上操作?→ 有,必须用 synchronized
- 要不要保证 A 和 B 两个变量的修改同时生效(比如余额减 X、流水加一条)?→ 要,只能靠 synchronized(或更高级的并发工具)

















