synchronized通过“锁机制+内存屏障”协同保障原子性和可见性:原子性靠互斥执行确保临界区操作不可分割,可见性靠happens-before规则及StoreLoad等内存屏障强制刷新和重读共享变量。

synchronized 通过“锁机制 + 内存屏障”协同作用,同时保障可见性和原子性,不是单靠加锁完成的,背后有 Java 内存模型(JMM)的严格语义支撑。
可见性:靠 happens-before 和内存屏障强制同步
当一个线程退出 synchronized 块时,JVM 保证它对共享变量的所有修改都刷新到主内存;另一个线程在进入同一把锁的 synchronized 块前,必须从主内存重新加载这些变量。
- 解锁操作(monitorexit)happens-before 后续对同一锁的加锁操作(monitorenter),这是 JMM 明确规定的 happens-before 规则
- JVM 在 monitorexit 后插入 StoreLoad 屏障,确保写操作对其他线程可见
- JVM 在 monitorenter 后插入 LoadLoad 和 LoadStore 屏障,强制清空工作内存并读取最新值
- 只同步写、不同步读是无效的——读操作也必须在 synchronized 块内,否则可能看到过期值
原子性:靠互斥执行与临界区串行化
synchronized 把一段代码变成“不可分割”的执行单元,多个线程无法交错执行其中的操作,从而避免读-改-写等复合操作被中断或覆盖。
在调试 Java 后端 API 故障时使用此技能,尤其适用于以下任务:分析日志、跨 Controller、Service 和 Mapper 层追踪请求、定位异常根因、检查 SQL 执行或参数流转,以及生成简洁的诊断结论与修复方案。
- 线程必须先成功获取 monitor 锁才能进入同步块,未获得锁则阻塞等待
- 同一把锁保护的多个操作(如 count++、list.add())天然串行执行,不会被其他线程插队
- 锁对象必须一致:用 this、Class 对象或专用 lock 对象均可,但所有读写都得用同一个
- 不同锁之间互不影响——synchronized(a) 和 synchronized(b) 是两个独立的同步域
为什么 volatile 不行,而 synchronized 可以兼顾两者
volatile 能禁止重排序、保证可见性,但不提供互斥,所以像 i++ 这类三步操作仍会丢失更新;synchronized 则把整个操作包裹在独占执行的临界区内,既阻断并发,又触发内存同步。
立即学习“Java免费学习笔记(深入)”;
- volatile 适合状态标志位(如 running = false)、单次读/写场景
- synchronized 适合需要“读-改-写”原子性 + 结果立即可见的场景(如计数器、缓存更新、状态切换)
- 实际使用中,锁对象应私有且 final,避免被外部误用或替换

















