java 类加载机制中,类的初始化阶段是线程安全的。jvm 规范规定,在多线程环境下,如果多个线程同时尝试初始化同一个类,只有一个线程能够执行该类的初始化代码,其他线程会被阻塞等待,直到初始化完成。这种机制确保了类只被初始化一次,避免了重复初始化和数据不一致的问题。

类初始化过程中 JVM 如何处理并发请求?
JVM 通过内置的锁机制来处理并发请求。当一个线程开始初始化一个类时,它会获取该类的类对象锁(Class Object Lock)。其他试图初始化同一类的线程会进入等待状态,直到第一个线程完成初始化并释放锁。这个过程对开发者是透明的,不需要手动同步。

public class ClassLoaderDemo {
static {
System.out.println("Class is being initialized");
try {
Thread.sleep(2000); // Simulate long initialization
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Class initialization completed");
}
public static void main(String[] args) {
Thread t1 = new Thread(() -> {
System.out.println("Thread 1 starts");
Class.forName("ClassLoaderDemo");
System.out.println("Thread 1 ends");
});
Thread t2 = new Thread(() -> {
System.out.println("Thread 2 starts");
Class.forName("ClassLoaderDemo");
System.out.println("Thread 2 ends");
});
t1.start();
t2.start();
try {
t1.join();
t2.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
运行上述代码,输出结果如下:
立即学习“Java免费学习笔记(深入)”;
Thread 1 starts Class is being initialized Class initialization completed Thread 1 ends Thread 2 starts Thread 2 ends
从输出可以看出,尽管两个线程同时尝试初始化 ClassLoaderDemo 类,但只有第一个线程执行了静态初始化块,第二个线程直接跳过了初始化过程,说明 JVM 保证了类初始化的线程安全性。
类初始化失败后会发生什么?
如果在类初始化过程中发生错误(例如静态初始化块抛出异常),JVM 会将该类的状态标记为“错误状态”(Error State)。此后,任何尝试使用该类的操作都会抛出 NoClassDefFoundError 或 ExceptionInInitializerError。类一旦进入错误状态,就不会再次尝试初始化。

public class FailingClass {
static {
throw new RuntimeException("Initialization failed");
}
public static void main(String[] args) {
try {
Class.forName("FailingClass");
} catch (Exception e) {
e.printStackTrace();
}
}
}
运行上述代码,输出结果如下:
立即学习“Java免费学习笔记(深入)”;
java.lang.ExceptionInInitializerError Caused by: java.lang.RuntimeException: Initialization failed
这表明类初始化失败后,JVM 会记录错误状态,后续使用该类时会直接抛出异常,而不会重新尝试初始化。
类初始化是否受类加载器影响?
是的,类初始化与类加载器密切相关。每个类加载器维护自己的命名空间,不同类加载器加载的相同类名会被视为不同的类。因此,即使两个类具有相同的完全限定名,只要它们由不同的类加载器加载,它们的初始化过程也是独立的。这意味着一个类加载器中的类初始化不会影响另一个类加载器中的同名类。


















