Implementing singleton is quite simple task. The following steps have to be done:
- declare constructor as private to ensure that no instance of the class can be created
- implement public static method that returns the only instance of the class
Because the private constructor, no descendant of the class can be made, so it’s useful practice to declare the singleton class as final to indicate that.public final class SimpleSingleton {
private static final SimpleSingleton theInstance = new SimpleSingleton();
private String textAttribute;
private SimpleSingleton() {
textAttribute = "Some text";
}
public static SimpleSingleton getInstance() {
return theInstance;
}
public String getText() {
return textAttribute;
}
}
In the example above you can see that instance of the singleton is initialized in the same moment when the class is initialized. If the initialization of the singleton is quite timely-consuming task or it’s not even known whether the singleton would be used then it’s useful to put the initialization off to the first moment when the singleton is needed. Demonstration follows:
The above example can be safely used only in single threaded application. Because there is no synchronization of the code where the singleton is initialized, it can easily happen that two or more threads would enter the dangerous line. One solution is to synchronize whole method getInstance(), but then the synchronization check would be done whenever the method is called so that the performance would be quite low. The right solution is to synchronize only section where the instance is being initialized. Demonstration follows:public final class LazyInitializationSingleThreaded {
private static LazyInitializationSingleThreaded theInstance;
private LazyInitializationSingleThreaded() {
}
public LazyInitializationSingleThreaded getInstance() {
if (theInstance == null) {
// the dangerous line follows
theInstance = new LazyInitializationSingleThreaded();
}
return theInstance;
}
}
Keep in mind that singletons should not be serialized, because by de-serialization you get another instance of the singleton.public final class LazyInitializationMultiThreaded {
private volatile static LazyInitializationMultiThreaded theInstance;
private LazyInitializationMultiThreaded() {
}
public static LazyInitializationMultiThreaded getInstance() {
if (theInstance == null) {
synchronized (LazyInitializationMultiThreaded.class) {
if (theInstance == null) {
theInstance = new LazyInitializationMultiThreaded();
}
}
}
return theInstance;
}
}
The last and more complicated case is when the singleton is defined as abstract class with descendants and the singleton while being initialized chooses the right descendant. This is useful when you need to have more singletons of the single type with different behavior. Demonstration follows:
public abstract class SingletonInheritance {
private static class CheerfulSingleton extends SingletonInheritance {};
private static class SadSingleton extends SingletonInheritance {};
private static class DefaultSingleton extends SingletonInheritance {};
private static SingletonInheritance theInstance;
public static SingletonInheritance getInstance() {
if (theInstance == null) {
synchronized (SingletonInheritance.class) {
if (theInstance == null) {
String mood = System.getenv("MOOD");
if (mood == null) {
mood = "";
}
theInstance = chooseInstance(mood);
}
}
}
return theInstance;
}
private static SingletonInheritance chooseInstance(String mood) {
if (mood.equalsIgnoreCase( "CHEERFUL" ))
return new CheerfulSingleton();
else if (mood.equalsIgnoreCase( "SAD" ))
return new SadSingleton();
else
return new DefaultSingleton();
}
private SingletonInheritance() {
}
}
3 comments:
Hi,
nice blog. Found some interesting articles.
However, your implementation of LazyInitializationMultiThreaded is unfortunately not correct regarding synchronization. This type of synchronization attempt is called "double-checked locking". An elaborate article on this topic can be found here: http://www.ibm.com/developerworks/java/library/j-dcl.html
And here on a (even) more technical basis: http://www.cs.umd.edu/~pugh/java/memoryModel/DoubleCheckedLocking.html
Best regards
Marc
Great!! i 'm implemented this code in webservicesproxy who depends of project fase. Works perfect.
Multiple Instances Resulting from Incorrect Synchronization
// Also an error, synchronization does not prevent
// two calls of constructor.
public static MySingleton getInstance() {
if (_instance==null) {
synchronized (MySingleton.class) {
_instance = new MySingleton();
}
}
return _instance;
}
see http://java.sun.com/developer/technicalArticles/Programming/singletons/
Post a Comment