synchronized(x.class)锁住x类的唯一class对象,确保静态资源初始化串行化;它适用于开发者自定义的延迟静态初始化,而非jvm自动保证的类加载阶段初始化。

synchronized(X.class) 是 Java 中实现类级别同步的常用方式,特别适用于保护静态资源的初始化过程。它锁住的是 X.class 这个 Class 对象——JVM 中每个类有且仅有一个 Class 实例,因此这把锁是全局唯一的,能确保所有线程对静态成员的访问(包括初始化)串行化。
为什么静态初始化需要类锁保护
静态字段、静态代码块或静态方法中的初始化逻辑,属于类级别行为,不依赖具体对象实例。若多个线程同时触发类的首次使用(如调用静态方法、访问静态字段),可能引发竞态条件:
- 静态变量未完全赋值就被其他线程读取(如部分构造、字段为默认值)
- 静态代码块重复执行(虽然 JVM 保证类初始化只发生一次,但自定义初始化逻辑若写在普通静态方法中,就无此保障)
- 单例的双重检查锁定(DCL)中,
volatile字段配合synchronized(X.class)可安全发布实例
synchronized(X.class) 在静态初始化中的典型用法
它不是用于“类加载阶段”的 JVM 内部初始化(那是由 JVM 自动保证线程安全的),而是用于开发者自己编写的、需延迟或按需执行的静态初始化逻辑:
- 延迟加载静态配置:如从文件或数据库读取后缓存到 static final Map 中,首次访问时加锁初始化
-
静态工具类的线程安全初始化:例如一个
StringUtils类,内部维护一个静态正则 Pattern 缓存,首次构建时需同步 -
替代静态 synchronized 方法:当不想把整个方法设为 synchronized,只锁关键初始化段,可写成
synchronized (X.class) { ... }
对比其他静态初始化方式
它和几种常见方案各有适用场景:
- 静态代码块:由 JVM 保证只执行一次且线程安全,但无法延迟——类加载即执行,不适合按需初始化
-
static synchronized 方法:等价于
synchronized(X.class),但粒度更粗;若方法体较长,会阻塞所有后续静态调用 - AtomicBoolean + CAS:适合简单标志控制(如“是否已初始化”),避免锁开销;但初始化逻辑本身仍需同步或 CAS 保护
- Initialization-on-demand holder idiom(IoDH):利用内部静态类的加载机制实现懒汉式单例,完全无锁,但仅适用于单例场景
注意事项与常见误用
使用 synchronized(X.class) 时需注意:
- 锁对象必须是确切的类字面量,如
synchronized(MyClass.class),不能用this.getClass()或运行时获取的 Class 实例(可能因继承导致锁错对象) - 避免在非 final 类上使用,子类调用可能意外锁住父类 Class,造成意外交互
- 不要在构造方法里用它保护静态初始化——构造方法本身不能被 synchronized 修饰,且此时类可能尚未完成链接,
X.class虽可用,但语义混乱 - 若初始化逻辑耗时较长,考虑是否可拆分为“标记+异步加载”,避免长时间阻塞其他线程
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











