You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Java中类锁与类静态变量作为锁的效果是否一致?

结论

两种加锁方式效果完全不一致,根本实现不了相同的代码执行顺序控制,示例里的Approach2甚至连正常运行都做不到。

核心逻辑

Java里synchronized的内置锁是和具体对象实例强绑定的:只有多个线程争抢同一个对象的锁时,才会互斥阻塞、实现执行顺序控制;锁不同对象的代码块之间完全不会互相干扰。

两种写法的本质差异

  • Approach1 里的synchronized(A.class)锁的是JVM加载A类时全局唯一生成的Class<A>实例,也就是常说的类锁。所有拿A.class当锁的代码,都会争抢这同一个全局唯一的锁对象,天然具备全局互斥的基础。
  • Approach2 里的synchronized(A.age)锁的是静态变量age指向的对象实例,和A.class根本不是同一个对象,二者的锁完全独立,不会产生任何互斥效果,问题非常多:
    1. 示例代码里age没有赋初始值,默认是null,执行synchronized(A.age)时会直接抛出NullPointerException,代码直接崩溃。
    2. 就算提前给age赋初始值(比如public static Integer age = 18;),Integer本身是不可变类,只要代码里任意位置对age重新赋值(比如A.age = 20),后续线程拿到的锁就是新生成的Integer实例,和之前的锁根本不是同一个对象,锁会直接失效,多个线程可以同时钻进临界区执行。再加上市示例里age是public修饰的,外部任意代码都能随便改它的指向,锁的可靠性完全没有保障。
    3. 就算你严格保证age永远不被重新赋值、永远不为null,它和A.class仍然是两个完全独立的对象:持有A.class锁的线程,根本不会阻塞想要获取A.age锁的线程,两类临界区代码可以并行执行,完全达不到统一的顺序控制效果。
补充

要是真打算用静态变量当全局锁用,至少得满足两个硬要求:一是变量必须在类加载阶段就完成初始化,全程不能为null;二是变量必须加final修饰,保证引用指向的对象永远不会变。但就算做到这两点,这个静态变量锁和对应类的类锁也是完全独立的两把锁,不可能和类锁效果完全一致。

内容的提问来源于stack exchange,提问作者silver_coin

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.29 05:55:05