Singleton is one of those design patterns which is encountered by almost every software developer irrespective of their background. This fact can be attributed to the usefulness of the pattern itself.
Though critics have singled out singleton as an anti pattern, who feel that it is overly used.
Apart from design considerations, what is even more important is the way Singleton pattern is implemented. In this post i will walk through the implementation of a singleton starting from the naive approach to the fully functional thread safe implementation and in the last the most elegant solution using Java 5.0 additions to the language.
Though critics have singled out singleton as an anti pattern, who feel that it is overly used.
Apart from design considerations, what is even more important is the way Singleton pattern is implemented. In this post i will walk through the implementation of a singleton starting from the naive approach to the fully functional thread safe implementation and in the last the most elegant solution using Java 5.0 additions to the language.
Naive implementation: Traditional way requires to declare constructor's access specifier to be private/protected and using static factory method to retrieve the instance of class as shown below.
public class Singleton {
private final static Singleton INSTANCE = null;
protected Singleton() {}
public static Singleton getInstance() {
if(INSTANCE == null)
INSTANCE = new Singleton();
return INSTANCE
}
}
Disadvantages:
- This solution in not thread safe and in case of concurrent calls to
getInstance()can result in multiple instances of Singleton.
Thread Safe Implementation(s):
a)
a)
public class Singleton {
public final static Singleton INSTANCE = new Singleton();
protected Singleton() {}
public static Singleton getInstance() {
return INSTANCE;
}
}
Disadvantage:
- This implementation is particularly not suitable where lazy initialization is sought, for eg. where Singleton is used to encapsulate objects having large memory footprints.
b)
public class Singleton {
private static volatile Singleton INSTANCE;
// Protected constructor is sufficient to suppress unauthorized calls to the constructor
protected Singleton() {}
public static synchronized Singleton getInstance() {
if (INSTANCE == null)
INSTANCE = new Singleton();
return INSTANCE;
}
}
Disadvantage:
- The above solution though provides lazy initialization but have a performance drawback as every call to getInstance() method has to acquire class lock on Singleton to proceed.
Following implementations c) and d) address this performance drawback and also provides thread safe/lazy initialized behavior.
c)
Double check locking:
c)
Double check locking:
public class Singleton {
private static volatile Singleton INSTANCE;
// Protected constructor is sufficient to suppress unauthorized calls to the constructor
protected Singleton() {}
public static Singleton getInstance() {
if (INSTANCE == null)
synchronized(Singleton.class) {
if (INSTANCE == null)
INSTANCE = new Singleton();
}
}
return INSTANCE;
}
}
d)
This implementation rely on a static inner class SingletonHolder which provides the lazy behavior.
This implementation rely on a static inner class SingletonHolder which provides the lazy behavior.
public class Singleton {
protected Singleton() {}
/**
* SingletonHolder is loaded on the first execution of Singleton.getInstance()
* or the first access to SingletonHolder.instance , not before.
*/
private static class SingletonHolder {
private final static Singleton INSTANCE = new Singleton();
}
public static Singleton getInstance() {
return SingletonHolder.INSTANCE;
}
}
I personally favor implementation the above solution d) just for sheer elegance and simplicity.
Now as if it looks we have got the best Singleton implementation at place,
here is the caveat, all the solutions that we have encountered so far are vulnerable to serialization and reflection attacks.
Serialization problem:- As implicit Deserialization behavior of JVM rely on the call to default constructor of the object, checks are required in case the Singleton object is serializable. This can be done by overloading readResolve() method of the api.
Reflection attack:- Not many people know that, in a code trusted environment it is possible to invoke private constructors by using AccessibleObject api. Thus leading to more than one instance of Singleton.
There is one more solution which takes care of the above mentioned attacks and is also thread safe. Only drawback is that it runs on jvm's supporting latest versions of java starting from java5.
It relies on a single-element enum type paradigm as shown below:
public enum Singleton {
INSTANCE;
}
With this we come to the end of Singleton journey for now. Look out for the posts as I try to dissect some other design pattern.-:)
No comments:
Post a Comment