synchronized通过加锁机制确保同一时刻仅一个线程执行临界区代码,解决共享资源并发修改问题;它以this、Class对象或显式对象为锁,保障count++等复合操作的原子性、可见性与有序性。

synchronized 通过加锁机制确保同一时刻只有一个线程能执行被保护的代码段,从而解决多线程对共享资源的并发修改问题。它不阻止线程调度,而是让其他线程在尝试获取同一把锁时阻塞等待,直到锁被释放。
锁对象决定作用范围
锁对象不同,保护的粒度和生效范围完全不同:
- 修饰实例方法 → 锁的是 this(当前对象实例),多个线程调用同一个对象的该方法时互斥;但不同对象实例之间完全不干扰
- 修饰静态方法 → 锁的是 类的 Class 对象(如
MyClass.class),所有线程无论通过哪个实例或直接用类名调用,都竞争同一把锁 - 同步代码块 → 可显式指定任意对象作为锁,比如
synchronized(lockObj),更灵活但也更易出错——必须保证所有访问同一共享变量的路径都用同一个锁对象
为什么能防止 count++ 出错
count++ 看似一条语句,实际对应三条 CPU 指令:读取(load)、自增(add)、写回(save)。线程可能在任意指令间被切换,导致两个线程读到相同旧值、各自+1后写回,结果只+1一次。synchronized 把这三步包裹成一个不可分割的临界区:
Java项目代码review工具。分析Git变更+完整调用链路上下文,推断业务需求,进行多维度评分和分类汇总,生成完整PRD文档。包含细粒度Java代码审查清单(Null安全、异常处理、Streams、并发、equals/hashCode、资源管理、API设计、性能、MyBatis/ORM、事务边界、SQL/DD...
- 线程 A 进入 synchronized 块时获得锁,执行完整个 count++ 过程并退出块,锁自动释放
- 线程 B 在 A 未释放锁前无法进入该块,只能等待,避免了指令交错
- 即使方法内抛异常,锁也会自动释放,无需手动处理
常见误用与规避要点
很多线程安全问题不是没加锁,而是锁得不对:
立即学习“Java免费学习笔记(深入)”;
- 误用实例方法保护全局计数器:每个请求新建 Counter 实例,synchronized increment() 对不同对象无效 → 应改用 static synchronized 或锁
Counter.class - 用 new 出的对象或局部变量作锁:每次 new 都是新对象,锁不住共享状态 → 必须复用同一个锁对象(如 private final Object lock = new Object())
- 漏锁某条写路径:比如 map 的 put 加了锁,但 get 没加,或另一处直接修改了共享字段 → 所有读写共享变量的地方都要走同一把锁
性能与替代方案
synchronized 是 JVM 层面支持的重量级锁,简单可靠,但高并发下可能成为瓶颈:
- 若只是简单计数,优先考虑 AtomicInteger 等原子类,基于 CAS 实现无锁并发
- 若操作复杂或需条件等待,可配合 wait/notify 使用,但要注意必须在 synchronized 块内调用
- 对集合等大对象,比 synchronized 方法更推荐用 同步代码块 + 显式锁对象,缩小锁粒度,减少阻塞时间

















