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?
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.