跳转至

synchronized 如何保证原子性、可见性、有序性?

一、三大特性

特性 含义
原子性 操作不可分割,要么全做要么全不做
可见性 一个线程改了,其他线程立即看到
有序性 不被指令重排

二、原子性

synchronized 代码块同一时刻只允许一个线程进入:

synchronized (lock) {
    i++;
}

锁内代码作为整体执行,其他线程不能插入。底层是 monitor 的计数器和 OS 互斥量。

三、可见性

synchronized 释放锁时,会把所有修改刷回主内存;获取锁时,会清空工作内存,从主内存重新读。

线程 A 释放锁:
  把工作内存所有写刷新到主内存

线程 B 获取锁:
  清空工作内存,从主内存重新加载

这保证 A 在锁内的修改,B 获取锁后都能看到。

四、有序性

synchronized 禁止两种重排:

  • 临界区内的重排不能移出临界区
  • 编译器和 JIT 不会把临界区外的操作重排到临界区内。

但临界区内部的重排是允许的(单线程语义不变)。

五、和 volatile 对比

synchronized volatile
原子性
可见性
有序性 ✅(禁止移出移入) ✅(禁止 volatile 附近重排)
性能 阻塞,重 无锁,轻

六、底层实现

  • 原子性:monitorenter/monitorexit。
  • 可见性:锁的内存语义(JMM 规定),底层对应内存屏障。
  • 有序性:JIT 和编译器不会把临界区代码重排到锁外。

总结

synchronized 是"万能锁",三大特性都保证,代价是性能。volatile 只保证可见性和有序性,适合一写多读的状态标志。