synchronized修饰方法时,JVM自动在入口加锁、出口释放锁:实例方法锁this,静态方法锁Class对象;锁由monitorenter/monitorexit指令保证,异常时仍自动释放。

synchronized 修饰方法时,Java 会自动在方法入口加锁、出口释放锁,无需手动调用 lock/unlock。关键在于锁对象的确定:对于实例方法,锁是当前对象(this);对于静态方法,锁是该类的 Class 对象。
实例方法加锁:锁住当前对象
当 synchronized 修饰非静态方法时,JVM 在线程进入方法前尝试获取当前实例对象的内置锁(monitor lock)。如果锁已被其他线程持有,当前线程阻塞等待;获取成功后执行方法体,方法返回(无论正常结束还是抛异常)时自动释放锁。
例如:
public synchronized void transfer(Account to, double amount) {
this.balance -= amount;
to.balance += amount;
}
等价于:
立即学习“Java免费学习笔记(深入)”;
public void transfer(Account to, double amount) {
synchronized(this) {
this.balance -= amount;
to.balance += amount;
}
}
静态方法加锁:锁住类对象
static 方法属于类而非实例,因此锁对象是 MyClass.class。所有线程调用该静态同步方法时,都竞争同一把类锁。
例如:
public static synchronized void initConfig() { ... }
等价于:
立即学习“Java免费学习笔记(深入)”;
public static void initConfig() {
synchronized(MyClass.class) { ... }
}
锁的自动性与注意事项
- 锁的获取和释放由 JVM 在字节码层面插入 monitorenter / monitorexit 指令完成,开发者不可见但保证原子性
- 即使方法内部抛出未捕获异常,锁也会被自动释放(这是 synchronized 的核心优势之一)
- 不能继承同步语义:子类重写 synchronized 方法时,需显式加上 synchronized 修饰符才生效
- 锁的是对象引用,不是变量名或方法签名;多个 synchronized 实例方法共用同一个 this 锁,可能造成不必要的串行化
不推荐的“自动加锁”误解
有人误以为加了 synchronized 就“自动优化锁粒度”或“智能选择锁对象”,其实不然。JVM 不做任何锁升级、分段或读写分离——它只按规则绑定固定锁对象。若需更灵活控制(如可中断、超时、多条件等待),应使用 java.util.concurrent.locks.ReentrantLock 并手动管理。


















