Sunday, April 02, 2006

Singleton Pattern in Java 2

As discussed in the previous post "Singleton Pattern in Java", the standard way to implement singleton pattern in Java is by using a static member variable which is initialized in a static initializer block or a static method. This way the static variable will be initialized when the class is loaded. This prevents race conditions (that occur when instantiated in the getInstance() method). However, this implementation has some implications:
  • The singleton class is hard-coded into the classes that use it. It also goes against the principle of "design to interfaces".
  • Since the singleton handles its own configuration, there will be no central repository for configuring signletons. This makes managing singletons a pain, specially in complex applications with many singletons.
  • It is difficult to update the state of a singleton at runtime. It can be achieved through the use of factory classes and from within the singleton class.
The alternative approach would be to use a registry of singletons. The registry is also occasionally called "application context" or "applicatin toolbox". The registry is also a singleton itself (it can also be bound to a the JNDI context). The application can get to any other singleton instance using the registry instance. A singleton registry implementation is shown below:
public class SRegistry {
public static SRegistry REGISTRY = new SRegistry();
private static HashMap map = new HashMap();
private SRegistry() {
}

public static synchronized Object getInstance(String classname) {
Object singleton = map.get(classname);

if(singleton != null) {
return singleton;
}
try {
singleton = Class.forName(classname).newInstance();
}
catch(Exception e) {
e.printStackTrace();
}
map.put(classname, singleton);
return singleton;
}
}
This method of implementing singletons works well with interfaces, if the getInstance() method is modified to use a name and get the class name from the configuration values. Inspite of being extremely careful, we may end up with multiple instances of singletons with the use of serialization or because of multiple classloaders. It is possible to avoid multiple instances of singletons due to serialization by overriding the readResolve() method to return the single instance. The classloader problem can be overcome by specifying the classloader yourself as described in "Simply Singleton"

1 comment: