synchronized通过锁的进入和退出强制同步共享变量读写,保证内存可见性:进入时用Load屏障清空工作内存并重读主存,退出时用Store屏障将修改刷新回主存,并依托happens-before规则建立线程间可见性链条。

synchronized 本身不修饰变量,而是修饰代码块或方法;它通过锁的进入和退出动作,强制同步共享变量的读写,从而保证内存可见性。
进入同步块时强制重读主内存
线程在执行 synchronized 块前,JVM 会在 monitorenter 指令处插入 Load 屏障,清空当前线程工作内存中与该锁关联的变量副本,确保后续所有读操作都从主内存加载最新值。
- 例如:线程 B 进入
synchronized(obj)前,哪怕之前缓存过flag的旧值,也会丢弃并重新读取主内存中的flag - 这解决了“读不到最新写入”的问题,比如
ready = true后,另一线程能立刻感知到
退出同步块时强制刷新回主内存
线程在离开 synchronized 块时,JVM 会在 monitorexit 指令处插入 Store 屏障,将临界区内所有被修改的共享变量,全部写回主内存。
- 例如:线程 A 在同步块内执行了
count++和status = "done",退出时这两个变更都会刷新到主内存 - 其他线程下次获取同一把锁时,就能看到这些更新
依赖 happens-before 规则建立可见性链条
JMM 明确规定:unlock 操作 happens-before 后续对同一锁的 lock 操作。这个语义不是靠轮询或延迟实现的,而是由 JVM 在锁边界插入内存屏障来保障的。
立即学习“Java免费学习笔记(深入)”;
- 线程 A 解锁前的所有写操作,对线程 B 后续加同一把锁后的读操作可见
- 这种顺序约束让变量更新“来得及被看见”,而不是“碰巧被看见”
和 volatile 的关键区别
volatile 只对单个变量读写生效,且不阻塞线程;synchronized 是以整个临界区为单位进行内存同步:
- volatile 能让
flag的赋值立即被看到,但无法保证i++(读-改-写三步)不丢失更新 - synchronized 把整个
i++包裹起来,既禁止并发执行,又确保结果对其他线程及时可见


















