synchronized(this) 锁的是当前实例对象,仅对同一实例的多线程访问互斥,不同实例互不影响;synchronized(clazz.class) 锁的是类的class对象,实现全实例级互斥,适用于静态资源保护,但易引发性能瓶颈与死锁。

synchronized(this) 的作用域与风险
修饰实例方法或写成 synchronized(this) 时,锁对象是当前实例(即调用该方法的对象)。多个线程若操作的是**同一个对象实例**,就会竞争同一把锁;但若操作的是不同实例,则互不影响——它们各自持有一把独立的锁。
常见误区是误以为所有实例方法都“全局互斥”,其实不是。比如创建了 3 个 Counter 对象,每个对象被不同线程调用其同步方法,这 3 个线程不会阻塞彼此。
- 适合保护该对象内部状态(如
private int count) - 不能用于保护静态变量或跨实例共享资源
- 死锁常发生在嵌套调用中:线程 A 持有 obj1 锁,又尝试获取 obj2 锁;线程 B 持有 obj2 锁,又尝试获取 obj1 锁
synchronized(Clazz.class) 的作用域与风险
synchronized(Clazz.class) 或修饰静态方法时,锁对象是该类的 Class 对象,在 JVM 中唯一存在。这意味着:无论多少个实例、多少个线程,只要进入这个锁范围,就只能串行执行。
它适用于控制对静态成员、全局缓存、单例初始化等**类级别资源**的访问。
- 能保证跨所有实例的互斥性
- 容易成为性能瓶颈(高并发下争抢激烈)
- 死锁可能出现在混合使用场景:比如线程先持
this锁,再试图进入Clazz.class同步块;另一线程反向操作
死锁排查的关键线索
死锁不报错,程序只是“卡住”。可通过 jstack <pid></pid> 查看线程堆栈,重点关注:
- 线程状态为
BLOCKED,且 waiting to lock 后跟一个地址,同时 locked - 两个或多个线程形成环形等待链(A 等 B 的锁,B 等 C 的锁,C 又等 A 的锁)
- 锁地址对应的是
java.lang.Class实例(说明是Clazz.class锁)或普通对象(说明是this锁)
特别注意:字符串字面量(如 synchronized("lock"))会因字符串常量池复用,意外导致不同模块间锁冲突,应避免。
避免死锁的实用做法
核心原则是打破“循环等待”条件:
- 统一加锁顺序:约定所有代码按固定顺序申请锁(如总是先锁 class,再锁 this;或按对象 hash 值排序)
- 减少锁粒度:优先用
synchronized代码块而非整个方法,只锁真正共享的临界区 - 避免在持有锁时调用外部方法:尤其不要调用可能反过来请求其他锁的方法
- 考虑升级为
ReentrantLock:支持tryLock(timeout),可主动放弃避免无限等待
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











