Java 单例静态初始化中的死锁 类
Deadlock in Java Static Initialization of Singleton Classes
我正在 libgdx 设计一款游戏,我决定让某些管理器 class 成为单身人士,因为我注意到我经常只使用 class 的一个实例,然后通过构造函数将同一个实例传递给许多其他 classes,这是非常痛苦的。现在,我有一个管理器 class 在其构造函数中初始化许多其他 classes。我通过为每个 class 使用静态块初始值设定项来做到这一点,如下所示:
public class Example{
private static Example instance;
static{
try{
synchronized(Example.class){
instance = new Example();
}
}catch(Exception e){
throw new RunTimeException("Failure to initialize Example instance");
}
public static Example getInstance(){
return instance;
}
在主管理器中,我通过 getInstance 方法为每个 class 创建了一个实例。
出现的问题是这样的:假设我有静态单例 classes Example1 和 Example2。
在 Example1 的构造函数中,我创建了一个名为:
的变量
example2 = Example2.getInstance();
但是因为 example2 和 example1 需要使用彼此的方法,所以在 Example2 的构造函数中我做了:
example1 = Example1.getInstance();
问题应该很容易看出来。因为 example1 正在等待 example2 完成初始化,而 example2 需要 example1 的实例,它最终通过上述代码 RunTimeException 创建死锁并崩溃。
这似乎很容易使用两个示例 classes 来解决,但是当我有 6 个不同的单例管理器 classes 时,问题就很复杂了,几乎都需要以某种方式进行通信。最简单的解决方案显然不会使用这种方法,但这需要我重写大部分代码。
我不知道如何在没有 运行 的情况下使用单例 classes 的这种方法解决这个问题,因为大多数 classes 需要来自其他 classes 的信息=31=]es在构造函数中才能发挥作用。
我是从单例 classes 的构造函数中删除所有代码,还是做其他事情?
不是死锁,是无限递归。没有办法解决它,你必须重构你的代码。
最好不要在你的构造函数中有任何逻辑,只有成员变量的初始化。由于您不需要将单例作为成员存储在 类 中,因此实际上不需要在构造函数中访问它们。只需使用适当的 getInstance() 方法从其他单例的方法内部访问单例。
我不再使用很多单例了。我认为单例是一个用例,而不是"type of class",然后依赖其他东西来管理它的"singleton-ness"(比如注入框架)。当我没有其中之一时,我创建了一个 "singleton" 来管理应用程序 classes-to-be-used-as-singletons.
因此,在这种情况下,您可以让这个 class 为您管理构造和相互依赖关系,而不是让 classes 自己管理它们。
public class Singletons {
private Example1 example1;
private Example2 example2;
private Example3 example3;
private static Singletons instance;
static {
Example1 example1 = new Example1();
Example2 example2 = new Example2();
Example3 example3 = new Example3();
instance = new Singletons();
example1 = new Example1();
example2 = new Example2();
example3 = new Example3();
example1.setExample2(example2);
example2.setExample3(example3);
example3.setExample1(example1);
instance.setExample1(example1);
instance.setExample2(example2);
instance.setExample3(example3);
}
public Example1 getExample1() {
return example1;
}
private void setExample1(Example1 example1) {
this.example1 = example1;
}
public Example2 getExample2() {
return example2;
}
private void setExample2(Example2 example2) {
this.example2 = example2;
}
public Example3 getExample3() {
return example3;
}
private void setExample3(Example3 example3) {
this.example3 = example3;
}
public Singletons getInstance() {
return instance;
}
}
我正在 libgdx 设计一款游戏,我决定让某些管理器 class 成为单身人士,因为我注意到我经常只使用 class 的一个实例,然后通过构造函数将同一个实例传递给许多其他 classes,这是非常痛苦的。现在,我有一个管理器 class 在其构造函数中初始化许多其他 classes。我通过为每个 class 使用静态块初始值设定项来做到这一点,如下所示:
public class Example{
private static Example instance;
static{
try{
synchronized(Example.class){
instance = new Example();
}
}catch(Exception e){
throw new RunTimeException("Failure to initialize Example instance");
}
public static Example getInstance(){
return instance;
}
在主管理器中,我通过 getInstance 方法为每个 class 创建了一个实例。
出现的问题是这样的:假设我有静态单例 classes Example1 和 Example2。
在 Example1 的构造函数中,我创建了一个名为:
example2 = Example2.getInstance();
但是因为 example2 和 example1 需要使用彼此的方法,所以在 Example2 的构造函数中我做了:
example1 = Example1.getInstance();
问题应该很容易看出来。因为 example1 正在等待 example2 完成初始化,而 example2 需要 example1 的实例,它最终通过上述代码 RunTimeException 创建死锁并崩溃。
这似乎很容易使用两个示例 classes 来解决,但是当我有 6 个不同的单例管理器 classes 时,问题就很复杂了,几乎都需要以某种方式进行通信。最简单的解决方案显然不会使用这种方法,但这需要我重写大部分代码。
我不知道如何在没有 运行 的情况下使用单例 classes 的这种方法解决这个问题,因为大多数 classes 需要来自其他 classes 的信息=31=]es在构造函数中才能发挥作用。
我是从单例 classes 的构造函数中删除所有代码,还是做其他事情?
不是死锁,是无限递归。没有办法解决它,你必须重构你的代码。
最好不要在你的构造函数中有任何逻辑,只有成员变量的初始化。由于您不需要将单例作为成员存储在 类 中,因此实际上不需要在构造函数中访问它们。只需使用适当的 getInstance() 方法从其他单例的方法内部访问单例。
我不再使用很多单例了。我认为单例是一个用例,而不是"type of class",然后依赖其他东西来管理它的"singleton-ness"(比如注入框架)。当我没有其中之一时,我创建了一个 "singleton" 来管理应用程序 classes-to-be-used-as-singletons.
因此,在这种情况下,您可以让这个 class 为您管理构造和相互依赖关系,而不是让 classes 自己管理它们。
public class Singletons {
private Example1 example1;
private Example2 example2;
private Example3 example3;
private static Singletons instance;
static {
Example1 example1 = new Example1();
Example2 example2 = new Example2();
Example3 example3 = new Example3();
instance = new Singletons();
example1 = new Example1();
example2 = new Example2();
example3 = new Example3();
example1.setExample2(example2);
example2.setExample3(example3);
example3.setExample1(example1);
instance.setExample1(example1);
instance.setExample2(example2);
instance.setExample3(example3);
}
public Example1 getExample1() {
return example1;
}
private void setExample1(Example1 example1) {
this.example1 = example1;
}
public Example2 getExample2() {
return example2;
}
private void setExample2(Example2 example2) {
this.example2 = example2;
}
public Example3 getExample3() {
return example3;
}
private void setExample3(Example3 example3) {
this.example3 = example3;
}
public Singletons getInstance() {
return instance;
}
}