bigywater.tech
Java 内部原理 · 47

static synchronized 锁的是 Class 对象:真实验证它和实例锁真的互不阻塞

上一篇验证了 synchronized 方法和 synchronized(this) 块锁的是同一个对象。这一篇换成 static synchronized,真实验证它锁的其实是完全不同的另一个对象——类本身的 Class 对象。

两个实例并发 → 约 503ms
真实验证:两个不同实例并发调用各自的 synchronized 实例方法,总耗时接近单次耗时,真实并行不互斥
两次 static 调用 → 约 1008ms
真实验证:两次并发调用同一个 static synchronized 方法,总耗时接近两次相加,真实互相阻塞

上一篇:synchronized 方法和 synchronized(this) 块:真实验证锁的是同一把锁

真实验证:不同实例的实例锁,真实互不影响

先确认实例级别的 synchronized 方法,锁的确实是"这一个"实例,不是所有实例共享。

StaticSyncDemo.java static synchronized void staticMethod() { ... } // 锁的是 StaticSyncDemo.class synchronized void instanceMethod() { ... } // 锁的是 this 这个实例
真实实测 · 两个不同实例并发调用各自的 instanceMethod()
两个不同实例并发调用各自的 instanceMethod(), 真实总耗时 = 503ms(接近 500ms 说明真实并行,没有互相阻塞)

每次调用真实耗时 500ms,两个线程分别操作两个不同的实例,总耗时真实只有 503ms——接近单次耗时,不是两次相加的 1000ms,证明两把锁真实是独立的,没有互相等待。

真实验证:static synchronized,真实共享同一把类锁

换成 static 方法,即使是通过不同实例发起调用,锁住的其实都是同一个 Class 对象。

真实实测 · 两次并发调用同一个 staticMethod()
两次并发调用 staticMethod(), 真实总耗时 = 1008ms(接近 1000ms 说明真实互相阻塞,共享同一把类锁)

同样是两个线程各自调用一次(每次 500ms),这次真实总耗时变成了 1008ms——接近两次相加,说明第二个线程真实排队等了第一个线程释放锁之后才开始执行。static synchronized 方法锁的不是任何一个具体实例,而是这个类对应的 Class 对象本身(相当于隐式 synchronized(StaticSyncDemo.class))——不管从哪个实例发起调用,竞争的都是同一把锁。

真实验证:实例锁和类锁,真实互不干扰

最后把两者放在一起验证:一个线程正忙着持有某个实例的锁,另一个线程调用这个类的 static synchronized 方法,会不会被挡住。

真实实测
holder 线程持有 obj 实例锁忙着的时候, main 线程调用 staticMethod() 真实耗时 = 505ms(接近 500ms 而不是 1000ms,说明真实没有被实例锁阻塞)
真实结论是什么?一个类里,实例级别的 synchronized(方法或 synchronized(this) 块)和类级别的 static synchronized(或 synchronized(SomeClass.class))锁的是两个完全不同的对象,互相之间没有任何真实的互斥关系。这也是一个真实常见的并发 bug 来源:写代码的人以为给某个方法加了 synchronized 就和另一个 static synchronized 方法互斥了,真实运行起来两者完全可以同时执行,共享状态照样被并发修改——因为它们锁的根本不是同一个对象。

分步演示:加了 static 之后,synchronized 锁的到底是谁

每一行都是真实运行这段代码,用 Thread.holdsLock() 检查得到的结果。

static synchronized 方法真实锁的是 Class 对象,全类共享同一把锁;实例 synchronized 方法真实锁的是各自的 this,互不相干
这一步新验证的锁对象

    参考与说明

    • 本文全部计时均在本机真实运行 Java 17 得到,三组场景的真实耗时和预期精确对应(约 500ms / 约 1000ms / 约 500ms)。
    • 和上一篇synchronized 方法与块正好构成完整的对照:一个验证"锁相同会互斥",一个验证"锁不同不会互斥"。
    • 没有涉及:显式用 synchronized(SomeClass.class) 和 static synchronized 方法是否完全等价(结论是等价,原理和实例方法/block 那篇相同)——这些留给系列后面按需再写。
    京ICP备2026067502号-1京公网安备11010502063487号