static synchronized 锁的是当前类的 class 对象(如 demo.class),而非实例或方法本身;所有线程调用该类任意 static synchronized 方法时均竞争同一把锁,等价于 synchronized(demo.class)。

static synchronized 到底锁的是谁?
它锁的是当前类的 Class 对象,比如 Demo.class,不是某个实例,也不是“静态方法本身”。JVM 里每个类有且仅有一个 Class 实例,所以所有线程调用该类任意 static synchronized 方法时,都得抢同一把锁。
- 等价写法:
synchronized(Demo.class) { ... }—— 显式写出锁对象,更直观 - 和非静态
synchronized方法完全无关:一个线程在执行instanceMethod()(对象锁),另一个完全可以同时执行staticMethod()(类锁) - 哪怕你 new 出一百个
Demo实例,调用它们各自的staticMethod(),仍是串行的
对象锁和类锁混用时,为什么数据还是乱?
因为二者互不干扰,但你要保护的数据可能横跨两个域。比如在对象锁方法里直接读写 static int counter,那这个静态变量就暴露在竞态下——对象锁管不到它,类锁又没被用上。
- 常见错误现象:
incrementInstance()里 ++ 了staticCount,却没加synchronized(MyClass.class) - 正确做法:操作静态资源,必须显式或隐式使用类锁;操作实例字段,才用对象锁
- 不要指望“我用了 synchronized 就万事大吉”——得看锁住的到底是不是你要保护的那个东西
什么时候该用类锁?别一上来就 static synchronized
类锁是全局锁,容易成瓶颈。只在真正需要“全局限制”时才用,比如单例初始化、配置加载、静态计数器归零等。
- 典型场景:
Logger.setLevel()、ConnectionPool.getInstance()、ConfigLoader.reload() - 性能影响:高并发下调用
static synchronized方法,吞吐量会明显下降 - 实操建议:优先考虑双重检查锁(DCL)+
volatile,比纯static synchronized更轻量;静态工具类方法若无需状态共享,干脆设计成无状态、线程安全的纯函数
synchronized(this) 和 synchronized(MyClass.class) 能否替换?
不能。它们锁的对象完全不同,语义不可互换。误换会导致要么锁失效(并发未控制),要么过度串行(性能受损)。
立即学习“Java免费学习笔记(深入)”;
- 想保护
this.cache或this.id?只能用synchronized(this)或非静态synchronized方法 - 想保护
MyClass.globalId或确保某段初始化只跑一次?必须用synchronized(MyClass.class)或static synchronized - 最容易踩的坑:在工厂方法里对临时对象加锁,比如
synchronized(new Object())—— 每次都是新对象,锁根本不起作用
最常被忽略的一点:锁对象本身要是稳定的。用 this 前确认它不会被外部替换;用 MyClass.class 是安全的,但用字符串字面量或临时容器当锁,就等于没锁。










