synchronized 如何保证原子性、可见性、有序性?¶
一、三大特性¶
| 特性 | 含义 |
|---|---|
| 原子性 | 操作不可分割,要么全做要么全不做 |
| 可见性 | 一个线程改了,其他线程立即看到 |
| 有序性 | 不被指令重排 |
二、原子性¶
synchronized 代码块同一时刻只允许一个线程进入:
锁内代码作为整体执行,其他线程不能插入。底层是 monitor 的计数器和 OS 互斥量。
三、可见性¶
synchronized 释放锁时,会把所有修改刷回主内存;获取锁时,会清空工作内存,从主内存重新读。
这保证 A 在锁内的修改,B 获取锁后都能看到。
四、有序性¶
synchronized 禁止两种重排:
- 临界区内的重排不能移出临界区。
- 编译器和 JIT 不会把临界区外的操作重排到临界区内。
但临界区内部的重排是允许的(单线程语义不变)。
五、和 volatile 对比¶
| synchronized | volatile | |
|---|---|---|
| 原子性 | ✅ | ❌ |
| 可见性 | ✅ | ✅ |
| 有序性 | ✅(禁止移出移入) | ✅(禁止 volatile 附近重排) |
| 性能 | 阻塞,重 | 无锁,轻 |
六、底层实现¶
- 原子性:monitorenter/monitorexit。
- 可见性:锁的内存语义(JMM 规定),底层对应内存屏障。
- 有序性:JIT 和编译器不会把临界区代码重排到锁外。
总结
synchronized 是"万能锁",三大特性都保证,代价是性能。volatile 只保证可见性和有序性,适合一写多读的状态标志。