synchronized通过“排队进门”机制解决多线程并发修改变量导致结果错误的问题,其本质是利用对象锁(Mark Word)实现互斥访问,并兼顾可见性、有序性和可重入性。

初学者理解 synchronized 的同步原理,关键不是死记“锁对象”或“Monitor”,而是抓住它解决的实际问题:多个线程同时改同一个变量时,结果可能出错。比如 count++ 看似一步,实际是“读值→加1→写回”三步,线程A读到5、还没写回时,线程B也读到5,最后两个都写6——本该是7,却变成了6。
它靠“排队进门”来保证安全
Java 给每个对象配了一把“门禁卡”(本质是对象头里的 Mark Word),synchronized 就是让线程进门(执行代码)前必须刷卡。只有拿到卡的线程能进去,其他线程在门口等着,等里面人出来还卡,下一个才能进。
- 修饰实例方法 → 刷的是
this对象的卡 - 修饰静态方法 → 刷的是当前类的
Class对象的卡(全类共用一把) - 修饰代码块 → 明确指定刷哪个对象的卡,比如
synchronized(obj)
JVM 底层其实是两条指令在干活
编译后,synchronized 块会变成 monitorenter 和 monitorexit 这两条字节码指令:
-
monitorenter:线程尝试刷卡,成功就进门,失败就挂起等待 -
monitorexit:出门时自动还卡,还会把修改过的变量立刻刷回主内存,确保别人能看到最新值 - 即使代码中途抛异常,JVM 也会保证
monitorexit执行,不会丢卡
锁不是一上来就“ heavyweight”(重量级)
为了不一上来就让线程挂起(开销大),JVM 设计了锁升级机制:
分析 Java Spring Boot 后端 Controller 代码,自动生成 Markdown 格式的接口文档。当用户说“生成 Java 接口文档”、“生成 API 文档”、“从 Spring 代码生成文档”时触发。
立即学习“Java免费学习笔记(深入)”;
- 没竞争时 → 偏向锁:直接把卡“绑定”给第一个线程,下次它来不用再刷
- 有轻微竞争 → 轻量级锁:用线程栈里的一个记录(Lock Record)做轻量协调
- 竞争激烈 → 升为重量级锁:真正进入操作系统级的等待队列(这时才真正“挂起”)
整个过程对开发者透明,你只管写 synchronized,JVM 自己优化。
它同时解决了三个并发难题
不只是“不让乱改”,它还顺带搞定另外两件事:
- 可见性:释放锁时,强制把本地修改写回主内存;加锁时,强制从主内存重新读值
- 有序性:禁止把锁内的代码重排序到锁外,保证逻辑顺序
- 可重入:同一个线程可以多次“刷卡”进门,不会把自己锁在外面
不复杂但容易忽略。

















