1. synchronized(同步锁)
- 核心作用
提供 原子性(Atomicity) 和 可见性(Visibility) 的双重保障。 - 工作原理
- 通过获取对象的 内置锁(Monitor Lock),确保同一时刻只有一个线程能执行同步代码块或方法。
- 在锁释放时,强制将线程本地内存的修改刷新到主内存(保证可见性)。
- 特性
- 原子性:保护代码块或方法的执行不可分割。
- 互斥性:同一时间仅允许一个线程访问资源。
- 可重入性:线程可以重复获取自己持有的锁。
- 适用场景
需要保证多个操作的原子性(如共享变量的复合操作i++)或复杂代码块的线程安全。
示例:
public class Counter {
private int count = 0;
public synchronized void increment() {
count++; // 原子操作
}
}
2. volatile(易变变量)
- 核心作用
仅保证变量的 可见性 和 禁止指令重排序,不提供原子性。 - 工作原理
- 通过强制线程直接从主内存读写变量,绕过本地缓存。
- 通过内存屏障(Memory Barrier)禁止编译器或 CPU 对指令重排序。
- 特性
- 可见性:变量的修改对所有线程立即可见。
- 有序性:禁止指令重排序优化(遵循 Happens-Before 规则)。
- 适用场景
单一变量的读写操作,且不依赖当前值的复合操作(如状态标志位)。
示例:
public class StatusChecker {
private volatile boolean running = true;
public void stop() {
running = false; // 其他线程立即可见
}
}
3. 关键区别
| 特性 | synchronized | volatile |
|---|---|---|
| 原子性 | ✅ 保证代码块或方法的原子性 | ❌ 不保证原子性 |
| 可见性 | ✅ 通过锁释放刷新主内存 | ✅ 直接读写主内存 |
| 有序性 | ✅ 同步块内的代码有序执行 | ✅ 禁止指令重排序 |
| 互斥性 | ✅ 同一时间仅一个线程访问 | ❌ 允许多线程并发读写 |
| 性能影响 | 高(涉及锁竞争和上下文切换) | 低(无锁机制) |
| 适用范围 | 复杂逻辑或多步操作的同步 | 单一变量的可见性控制 |
4. 典型使用场景
-
synchronized- 复合操作(如
i++、check-then-act)。 - 需要互斥访问共享资源(如文件写入、数据库连接池)。
- 复合操作(如
-
volatile- 状态标志位(如
boolean running)。 - 单次写入、多次读取的变量(如配置参数)。
- 状态标志位(如
5. 注意事项
-
volatile的局限性
即使变量是volatile,类似count++的操作仍是非原子的,需结合AtomicInteger或synchronized。 -
synchronized的优化
JDK 1.6 后引入锁消除、锁粗化、偏向锁等优化,降低性能开销。
总结
- 需要 原子性 或 互斥访问 → 用
synchronized。 - 只需 可见性 或 禁止重排序 → 用
volatile。
两者可结合使用(如用volatile状态标志控制同步块的执行)。

1193

被折叠的 条评论
为什么被折叠?



