Java中synchronized保证临界区独占的关键是所有线程必须竞争同一把锁;同步实例方法锁this,静态方法锁Class对象,代码块锁指定obj,须确保锁对象唯一且不变,粒度应覆盖完整共享数据操作。

Java 中用 synchronized 保证临界区独占,核心是让多个线程竞争同一把锁,从而确保任意时刻最多只有一个线程能执行该段代码。关键不在“怎么写”,而在于“锁什么”和“锁多大范围”。
临界区必须用同一把锁保护
临界区指访问共享变量或资源的那段代码。要让它真正互斥,所有线程执行这段代码时,必须尝试获取**同一个对象锁**。否则,各锁各的,就形同虚设。
- 同步实例方法(
public synchronized void method())→ 锁的是当前对象this - 同步静态方法(
public static synchronized void method())→ 锁的是当前类的Class对象 - 同步代码块(
synchronized(obj) { ... })→ 锁的是括号里明确指定的obj,必须确保所有线程传入的是同一个对象引用
避免常见锁对象错误
锁对象一旦选错,临界区就失去互斥意义:
当用户要求为 Java 代码添加注释、修改注释、审查注释、整理注释格式,或要求按照代码注释规范处理 Java 文件时,使用本技能。本技能用于统一生成和维护 Java 类注释模板、按 Git 对比 release 判断版本号、补充每行代码上方中文块注释、调整注释空行规则,并保持 Java 文件 UTF-8 无 BOM 编码。典型触发场景包括:补充类注释、更新 @version、检查 @author 来源、整理行尾注释、把注释放到代码上一行、检查注释是否符合规范、构建前检查 Java 注释风格。
- 别用每次 new 出来的对象作锁(如
synchronized(new Object())),每个线程锁的都不是同一个对象 - 别用可变的、可能被重新赋值的引用(如
String s = "a"; synchronized(s) { s = "b"; }),后续同步块可能锁了不同对象 - 实例方法和同步代码块混用时,注意是否都锁
this;若代码块锁的是别的对象(比如private final Object lock = new Object()),那它和synchronized实例方法互不干扰
合理控制临界区粒度
临界区不是越小越好,也不是越大越安全,得看共享数据的边界:
立即学习“Java免费学习笔记(深入)”;
- 如果只有一行代码修改一个
int count,且其他地方不读写它,那锁住这一行就够了 - 但如果要“读→改→写”三步(如
if (count ),这整个逻辑必须包在一个同步块里,拆开会破坏原子性 - 不要把耗时操作(如 I/O、网络调用)放进同步块,否则其他线程会长时间等待,影响吞吐
锁的可见性天然保障临界区内共享变量
synchronized 不仅保证互斥,还保证内存可见性:一个线程在释放锁前对共享变量的修改,另一个线程在获取同一把锁后一定能立即看到。
- 这意味着,只要所有对某变量的读写都发生在同一把锁保护的临界区内,这个变量就不需要额外加
volatile - 但若某个变量既在同步块内被修改,又在同步块外被读取,那就存在可见性风险,应统一纳入锁保护,或改用
volatile+ 其他机制

















