-2

我在 libgdx 中设计游戏,我决定将某些管理器类设为单例,因为我注意到我经常只使用一个类的一个实例,然后通过构造函数将同一个实例传递给许多其他类,这非常痛苦做。现在,我有一个管理器类,它在它的构造函数中初始化了许多其他类。我通过为每个类使用静态块初始化器来做到这一点,如下所示:

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 方法为每个类创建一个实例。

出现的问题是:假设我有静态单例类 Example1 和 Example2。
在 Example1 的构造函数中,我创建了一个名为:

    example2 = Example2.getInstance();

但是因为 example2 和 example1 需要使用彼此的方法,所以在 Example2 的构造函数中我做了:

    example1 = Example1.getInstance();

问题应该很容易看出。因为example1在等待example2完成初始化,而example2又需要example1的实例,最终通过上面的代码RunTimeException造成死锁崩溃。

仅使用两个示例类似乎很容易解决这个问题,但是当我有 6 个几乎都需要以某种方式进行通信的不同单例管理器类时,问题就变得复杂了。最简单的解决方案显然不会使用这种方法,但这需要我重写我的大部分代码。

我不知道如何在不遇到这个问题的情况下使用这种单例类方法,因为大多数类需要来自构造函数中其他类的信息才能运行。
我要从单例类的构造函数中删除所有代码,还是做其他事情?

4

2 回答 2

1

这不是死锁,而是无限递归。没有办法解决它,你必须重构你的代码。

最好的事情是在你的构造函数中没有任何逻辑,只是初始化成员变量。由于您不需要将单例存储为类中的成员,因此确实不需要在构造函数中访问它们。只需使用适当的 getInstance() 方法从其他单例的方法中访问单例。

于 2018-01-13T04:20:20.787 回答
0

我不再使用很多单例了。我认为单例是一个用例,而不是“类的类型”,然后依靠其他东西来管理它的“单例”(例如注入框架)。当我没有其中一个时,我会创建一个“单例”来管理要用作单例的应用程序类。

因此,在这种情况下,您可以让这个类为您管理构造和相互依赖关系,而不是让这些类自己管理它们。

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;
    }
}
于 2018-01-13T04:24:37.667 回答