摘要
在 Java 并发编程中,synchronized
既可以作用于对象实例(对象锁),也可以作用于类对象(类锁)。很多开发者容易混淆二者,导致锁使用不当。本文深入解析对象锁与类锁的区别、适用场景,并结合代码示例帮助你彻底搞懂。
正文
一、对象锁与类锁的概念
- 对象锁(Instance Lock)
- 通过
synchronized
修饰 实例方法 或 对象实例代码块。 - 锁定的粒度:当前对象实例(this) 。
- 多个对象实例之间互不影响。
java
public synchronized void instanceMethod() {
// 对象锁,锁住 this
}
- 类锁(Class Lock)
- 通过
synchronized
修饰 静态方法 或 类对象代码块。 - 锁定的粒度:Class 对象(Class<?> clazz) 。
- 整个类范围内共享同一把锁。
java
public static synchronized void staticMethod() {
// 类锁,锁住 MyClass.class
}
二、对象锁 vs 类锁的区别
对比维度 | 对象锁 | 类锁 |
---|---|---|
锁定范围 | 单个实例 | 整个类 |
锁对象 | this(实例) | Class 对象 |
并发影响 | 多个实例可并行 | 整个类只能一个线程进入 |
使用场景 | 保护实例字段 | 保护静态字段或全局资源 |
是否互斥 | 不与类锁互斥 | 不与对象锁互斥 |
三、代码示例
1. 对象锁互斥(不同线程访问同一实例)
java
public class Demo {
public synchronized void instanceMethod() {
System.out.println(Thread.currentThread().getName() + " 进入对象锁方法");
try { Thread.sleep(2000); } catch (InterruptedException e) {}
System.out.println(Thread.currentThread().getName() + " 退出对象锁方法");
}
public static void main(String[] args) {
Demo demo = new Demo();
new Thread(demo::instanceMethod, "T1").start();
new Thread(demo::instanceMethod, "T2").start();
}
}
结果:T1
与 T2
串行执行,因为它们竞争的是同一个对象锁。
2. 多个对象实例(对象锁不互斥)
java
Demo d1 = new Demo();
Demo d2 = new Demo();
new Thread(d1::instanceMethod, "T1").start();
new Thread(d2::instanceMethod, "T2").start();
结果:T1
和 T2
并发执行,因为它们持有不同对象的锁。
3. 类锁互斥(静态方法)
java
public static synchronized void staticMethod() {
System.out.println(Thread.currentThread().getName() + " 进入类锁方法");
try { Thread.sleep(2000); } catch (InterruptedException e) {}
System.out.println(Thread.currentThread().getName() + " 退出类锁方法");
}
即使是不同实例,调用该方法也会被互斥,因为锁住的是 Demo.class
。
四、常见误区
- 以为对象锁和类锁会互斥
- 错误认识:对象锁和类锁会阻塞对方。
- 实际情况:它们互不干扰,一个线程拿对象锁,另一个线程拿类锁,能同时执行。
- 错误选择锁粒度
- 锁住
this
时要确保锁对象唯一,否则会失效。 - 静态变量竞争必须用类锁,否则无法保证一致性。
五、适用场景
- 对象锁
- 用于保护 实例变量;
- 适合在 多用户多对象 场景(如:每个用户购物车互不干扰)。
- 类锁
- 用于保护 静态变量/全局资源;
- 适合在 跨实例共享资源 场景(如:订单号生成器、配置缓存)。
六、总结
- 对象锁:锁住的是单个实例,适用于保护实例级资源。
- 类锁:锁住的是类对象,适用于保护类级资源。
- 二者不互斥:对象锁和类锁独立存在,不能相互替代。
- 最佳实践:根据资源粒度选择合适的锁,避免锁范围过大造成性能瓶颈。
理解对象锁 vs 类锁,是掌握 Java 并发编程中锁机制的关键一步。