synchronized通过锁机制、内存屏障和happens-before规则协同保障原子性与可见性:原子性靠互斥执行确保临界区操作不可分割,可见性靠释放锁时刷新主存、获取锁时重读主存,并遵循unlock-happens-before-lock规则。

synchronized 在 Java 内存模型(JMM)中,不是靠“加锁”这一个动作单独起作用的,而是通过锁机制 + 内存屏障 + happens-before 规则三者协同,同时保障可见性和原子性。
原子性:靠互斥执行确保操作不可分割
多个线程无法同时进入同一个 synchronized 代码块或同步方法,因为 JVM 要求线程必须先成功获取 monitor 锁;获取失败则阻塞等待。这就让临界区内的所有操作——哪怕包含读、改、写多步——被当作一个整体串行执行。
- 同一把锁(如
this或某个private final Object lock)保护的所有共享变量,其读写操作天然互斥 - 不同锁之间不构成同步关系:比如
synchronized(obj1)和synchronized(obj2)是完全独立的,不能保证跨锁操作的原子性 - 典型反例:
volatile int count的count++仍是非原子的,而synchronized包裹后就变成原子行为
可见性:靠锁进出时的内存同步强制刷新与重读
JMM 明确规定:
- 线程释放锁前,必须把工作内存中该锁所保护的共享变量最新值,刷新回主内存
- 线程获取锁时,必须清空工作内存中对应变量的副本,并从主内存重新加载最新值
这个过程由 JVM 在 monitorenter 和 monitorexit 指令处插入内存屏障(如 StoreLoad 屏障)来实现,确保不会因 CPU 缓存或编译器优化导致数据滞留。
立即学习“Java免费学习笔记(深入)”;
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
它背后遵循 happens-before 原则中的“监视器锁规则”:一个线程对某锁的 unlock 操作,happens-before 另一个线程对该锁的 lock 操作。这意味着前者的写,对后者可见。
关键使用前提:锁对象和访问范围必须一致
要真正发挥 synchronized 的 JMM 效果,必须满足两个硬性条件:
- 所有读写共享变量的操作,都必须在同一个锁对象的 synchronized 块内完成;只同步写、不同步读,读线程仍可能看到过期值
- 锁对象必须是同一个实例:用
this就统一用this,用私有 final 对象就始终用它,避免因锁对象不一致导致同步失效 - 锁粒度需合理:太粗(如整个方法)会降低并发度;太细(如每行都 new 一个锁)则失去保护意义
为什么 volatile 不行,而 synchronized 可以兼顾两者?
volatile 只能保证单次读/写的可见性和禁止重排序,但不提供原子性。例如 i++ 是“读-改-写”三步,即使 i 是 volatile,仍可能丢失更新。
synchronized 则把整个复合操作包裹起来:既阻止其他线程并发执行,又通过锁进出的内存语义,确保修改对后续获得同一锁的线程立即可见。它是 JMM 中更完整、更可靠的同步原语。

















