synchronized锁的是Java对象实例(如this、Class对象或自定义对象),而非字节码;修饰实例方法锁this,静态方法锁Class对象,代码块锁指定对象引用。

synchronized 并不锁定“字节码对象”,而是锁定一个**Java 对象实例(Object)**,这个对象作为监视器(monitor)。所谓“指定字节码对象”是一种常见误解——JVM 中的 class 文件(.class)被加载后变成 Class 类型的对象(即 MyClass.class),它本身是 Java 堆中的一个普通对象,可以被用作锁,但它不是“字节码”本身,也不是某种特殊字节码实体。
1. synchronized 锁的是对象引用,不是类定义或字节码
Java 中每个对象(包括数组、Class 对象、String 常量池中字符串等)都关联一个 monitor。synchronized 语法只是告诉 JVM:“当前线程必须先获取该对象的 monitor 锁,才能执行同步块”。所以:
-
synchronized(obj) { ... }→ 锁住的是obj这个对象实例(比如 new Object()、this、某个成员变量) -
synchronized(MyClass.class) { ... }→ 锁住的是MyClass对应的Class对象(由类加载器创建,全局唯一) -
synchronized(this) { ... }→ 锁住当前实例对象
2. 如何“指定”一个 Class 对象作为锁?
如果你希望多个线程在操作同一类的静态资源时互斥,常用方式就是用 MyClass.class 作为锁对象:
public class Counter {
private static int count = 0;
public static void increment() {
synchronized (Counter.class) { // ✅ 锁住 Counter 的 Class 对象
count++;
}
}
}
注意:Counter.class 是 JVM 在类加载阶段创建的 java.lang.Class<counter></counter> 实例,它存在于方法区(元空间),整个 JVM 中每个类只有一个这样的对象,因此能实现跨实例的静态同步。
立即学习“Java免费学习笔记(深入)”;
3. 不要误用字符串字面量或常量池对象作锁
以下写法危险且不可控:
synchronized ("lock") { ... } // ❌ 危险!字符串常量池共享,可能被其他无关代码锁住
因为 "lock" 是字符串字面量,会被放入字符串常量池,若其他类也用 "lock" 同步,就会意外竞争,导致死锁或性能瓶颈。同理,避免用 Integer.valueOf(127) 等缓存对象作锁。
4. 想精确控制锁粒度?推荐私有 final 锁对象
最清晰、安全的做法是声明一个私有的、final 的锁对象:
public class BankAccount {
private final Object lock = new Object(); // ✅ 明确、私有、不可变
private double balance;
public void withdraw(double amount) {
synchronized (lock) {
if (balance >= amount) {
balance -= amount;
}
}
}
}
这样既避免了锁暴露给外部,又不会和其它逻辑意外竞争,比用 this 或 getClass() 更可控(尤其在继承场景下)。
本质上,synchronized 的“指定对象”就是传入任意非 null 的 Java 对象引用;它背后依赖 JVM 对该对象头中 monitor 的管理机制,与字节码文件内容无关,也不需要你手动操作字节码。


















