我有以下三个类(class)。
BaseClass.java
public class BaseClass {
static {
load();
}
public static void init() {
System.out.println("base init");
}
private static void load() {
System.out.println("In load method of base class");
DerivedClass dc = new DerivedClass();
System.out.println("Object creation done.");
}
}
DerivedClass.java
public class DerivedClass extends BaseClass {
public DerivedClass() {
System.out.println("derived class constructor");
}
public static boolean isSynthetic(String _attr) {
return true;
}
}
Helper.java
public class Helper {
public static void main(String[] args) {
Thread t = new Thread() {
public void run() {
BaseClass.init();
};
};
t.start();
System.out.println("calling static method of derived class..");
System.out.println(DerivedClass.isSynthetic("test"));
}
}
当我从Helper.java执行main方法时,我得到以下输出-
执行停止后,进程仍在运行。
因此似乎有一些僵局,但我不明白为什么会这样。
需要帮助。
最佳答案
当第一次引用BaseClass
时,类加载器将启动并希望设置要使用的类。因此,它将加载该类并启动静态初始化程序块
static {
load();
}
这将调用
load
-method,然后您尝试在其中创建DerivedClass
类型的对象。这将首先尝试调用super()
-constructor,即BaseClass
类的方法-但BaseClass
尚未完全初始化,因为其静态初始值设定项尚未完成=>死锁。编辑:
根据您的评论,我进行了更多研究。实际上,事情并没有我想象的那么简单。 JVM能够处理递归初始化,因此在单线程情况下没有问题。可以在JVM规范的第5.5节中找到有关类初始化过程的描述。
真正的罪魁祸首实际上是两个初始化过程之间的竞争条件。
线程1到达
DerivedClass.isSynthetic("test")
,并开始DerivedClass
的初始化。同时,线程2到达
BaseClass.init()
并开始BaseClass
的初始化。在初始化
DerivedClass
线程1时,它认识到必须初始化父类(super class)。由于线程2已在进行BaseClass
的初始化,因此线程1必须等待其完成。在初始化
BaseClass
时,线程2到达DerivedClass dc = new DerivedClass();
。由于线程1已在进行DerivedClass
的初始化,因此线程2必须等待其完成。因此,实际上这是一个经典的死锁,其中两个线程尝试以不同的顺序(BaseClass-> DerivedClass与DerivedClass-> BaseClass)输入两个关键代码路径(“类X的初始化”),并最终互相等待。
在适当的位置添加一些
Thread.sleep(100);
也将向您表明这确实是一个竞争条件。在我的测试过程中,尽管初始化期间存在循环依赖性,但有时程序还是成功完成了。关于java - 在Java代码中陷入僵局,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/37959532/