synchronized通过锁机制将临界区代码串行化执行以保证原子性,本质是用对象监视器(monitor)互斥控制,使“读-改-写”等复合操作不可被中断;其原子性作用范围取决于锁对象,不同锁互不干扰。

synchronized 通过互斥执行临界区代码来保证原子性,本质是让多线程对共享资源的操作“串行化”。 它不靠单条 CPU 指令的不可分割(那是硬件层面),而是用锁机制阻止其他线程进入同一段受保护的代码,从而把原本可能被拆开、穿插执行的复合操作,变成一个不可打断的整体。
原子性问题的根源在于“读-改-写”三步分离
比如 count++ 看似一条语句,实际对应三个独立动作:
- 从主内存读取
count值到线程工作内存(读) - 在工作内存中加 1(改)
- 把新值写回主内存(写)
若两个线程同时执行这三步,就可能出现:都读到 0 → 都算出 1 → 都写回 1,最终结果还是 1。这就是非原子操作在并发下的典型丢失更新。
synchronized 怎么堵住这个漏洞
它不是让每一步变“原子”,而是让整个三步包裹成一块“禁区”:
分析 Java Spring Boot 后端 Controller 代码,自动生成 Markdown 格式的接口文档。当用户说“生成 Java 接口文档”、“生成 API 文档”、“从 Spring 代码生成文档”时触发。
- 线程 A 进入
synchronized块前,必须先获取对象监视器(monitor)锁 - 一旦拿到锁,其他线程尝试进入同一把锁保护的代码块时,会被阻塞等待
- A 执行完全部逻辑(包括读、改、写)并释放锁后,B 才能获得锁开始执行
- 即使 A 在执行中途被系统调度挂起,锁也不会释放,后续时间片仍由 A 继续执行,直到完成退出
关键点:锁对象决定串行范围
原子性只在“同一把锁”下成立,不同锁之间互不影响:
-
synchronized(this)和synchronized(otherObj)是两套独立的串行队列 - 静态方法用
Class对象作锁,实例方法默认用this,二者也不互斥 - 所以多个 synchronized 方法若锁对象不同,它们的执行仍可能交叉,无法构成整体原子性
和 volatile 的区别很说明问题
volatile 能让每次读都看到最新值(可见性),也能禁止某些重排序(有序性),但它不加锁:
- 对
volatile int i执行i++,读、改、写三步依然可被其他线程穿插 - 而
synchronized把这三步整个罩住,别人进不来,自然就不会被打断 - 所以 volatile 适合标志位这类单次读/写场景;synchronized 才适合计数、状态切换等需要多步一致性的操作
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










