javasingletonsingleton-methods

Deadlock in Java Static Initialization of Singleton Classes


I am designing a game in libgdx, and i decided to make certain manager classes singletons because I noticed that I was often only using one instance of a class, and then passing the same instance to many other classes through constructors, which was very painful to do. Now, I have one manager class that initializes many other classes in it's constructor. I did this by using static block initializers for each class, like so:

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;
       }  

In the main manager I create an instance of each class through the getInstance method.

The problem that arises is this: say I have static singleton classes Example1 and Example2.
In Example1's constructor I make a variable called:

    example2 = Example2.getInstance();

but because example2 and example1 need to use each other's methods, in Example2's constructor I make:

    example1 = Example1.getInstance();

The problem should be easy to see. Because example1 is waiting for example2 to finish initializing, and example2 needs example1's instance, it ends up creating a deadlock and crashing through the above codes RunTimeException.

this seems easy to fix using just two example classes, but the problem is confounded when I have 6 different singleton manager classes that almost all need to communicate in some way. Easiest solution would obviously not use this methodology, but that would require me to rewrite most of my code.

I can't figure out how to use this methodology of singleton classes without running into this issue, as most of the classes need information from the other classes in the constructor in order to function.
do I remove all of the code from the constructors of the singleton classes, or do something else?


Solution

  • I don't use many singletons any more. I consider a singleton to be a use case, rather than a "type of class", and then rely on something else to manage the "singleton-ness" of it (such as an injection framework). When I don't have one of those, I create a single "singleton" to manage the applications classes-to-be-used-as-singletons.

    So, in this case, you can have this class manage the construction and interdependencies for you rather than have the classes manage them for themselves.

    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;
        }
    }