synchronized通过互斥、可见性、原子性三重机制保障线程安全:锁住临界区实现互斥执行;释放锁时写回主内存、获取锁时重读变量保障可见性;将复合操作封装为不可分割单元提供原子性;底层依托monitor与内存屏障协同工作。

synchronized 通过“互斥 + 可见性 + 原子性”三重机制,确保多个线程对共享资源的操作不会相互干扰。它不是简单地“让代码变慢”,而是用锁的获取与释放建立严格的执行时序和内存同步规则。
锁住临界区,实现互斥执行
同一时刻,只有一个线程能进入被 synchronized 保护的代码块或方法(即临界区)。其他线程必须等待当前线程执行完并释放锁后,才能竞争进入。
- 修饰实例方法 → 锁对象是 this(当前实例)
- 修饰静态方法 → 锁对象是 类.class(如 MyClass.class)
- 修饰代码块 → 锁对象是括号中指定的对象,例如 synchronized(obj)
关键点:锁的是“对象”,不是“代码”。不同实例的 synchronized 实例方法可并发执行;同一个实例的方法则互斥。
强制刷新主内存,保障可见性
线程在释放锁前,会把工作内存中所有共享变量的最新值写回主内存;获取锁时,则会清空本地工作内存,并从主内存重新读取变量值。
这就避免了 volatile 的短板——volatile 只保证“读那一刻是最新的”,但不控制“读→算→写”整个流程;synchronized 在整个临界区结束时统一刷新,确保后续线程一定看到前一线程的全部修改。
包裹复合操作,提供原子性保障
像 count++ 这类操作实际包含“读、加1、写回”三步,非原子。synchronized 把这三步整体封装进一个不可分割的单元:
- 线程A进入 synchronized 块执行 count++,期间线程B无法进入同一把锁保护的区域
- 即使CPU调度切换,也不会出现“A读了0、B也读了0、A写1、B写1”的覆盖错误
- 结果严格符合预期:10个线程各执行1000次,最终 count = 10000
底层靠 Monitor 和内存屏障协同工作
JVM 为每个对象关联一个 Monitor(监视器),synchronized 编译后生成 monitorenter / monitorexit 字节码指令:
- monitorenter 触发锁竞争,成功则持有 Monitor,失败则进入 EntryList 阻塞等待
- monitorexit 不仅释放锁,还插入内存屏障(Memory Barrier),禁止相关读写指令重排
- 配合对象头中的 Mark Word 状态位(偏向锁→轻量级锁→重量级锁),实现锁的自适应优化
这套机制由 JVM 自动管理,无需手动 lock/unlock,也不怕异常导致锁未释放——monitorexit 在正常退出和异常退出时都会执行。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











