Singleton pattern is a design pattern that restricts the
instantiation of a class to one object.
This pattern involves a single class which is
responsible to creates own object while making sure that only single object get
created. This class provides a way to access its only object which can be
accessed directly without need to instantiate the object of the class
There are different ways /approaches
to achieve singleton design pattern
1)
Eager initialization: This is a design
pattern where an instance of a class is created much before it is actually
required. Mostly it is done on system start up. In singleton pattern, it refers
to create the singleton instance irrespective of whether any other class
actually asked for its instance or not.
public class Singleton {
private static final Singleton INSTANCE = new Singleton();
private Singleton() {}
public static Singleton getInstance() {
return INSTANCE;
}
}
Instance is created irrespective of it is required in runtime or not. If this instance is not big object and you can live with it being unused, this is best approach.
This
method has a number of advantages:
- The instance
is not constructed until the class is used.
- There is no
need to synchronize the getInstance() method, meaning all threads will see
the same instance and no (expensive) locking is required.
- The final
keyword means that the instance cannot be redefined, ensuring that one
(and only one) instance ever exis
2)
Lazy Initialization:
It is
the tactic of delaying the creation of an object, the calculation of a value,
or some other expensive process until the first time it is needed. In singleton
pattern, it restricts the creation of instance until requested first time
// Correct but possibly expensive multithreaded version
class Foo {
private Helper helper;
public synchronized Helper getHelper() {
if (helper == null) {
helper = new Helper();
}
return helper;
}
// other functions and members...
}
On first invocation, above method will check if
instance is already created using instance variable. If there is no instance
i.e. instance is null, it will create an instance and will return its
reference. If instance is already created, it will simply return the reference
of instance.But,
this method also has its own drawbacks. Lets see how. Suppose there are two threads T1 and T2. Both comes to create
instance and execute “instance==null”, now
both threads have identified instance variable to null thus assume they must create an instance. They sequentially goes to
synchronized block and create the instances.
At the end, we have two instances in our application.
This error can be solved using double-checked locking. This principle tells
us to recheck the instance variable again in synchronized block in given below
way:
// Broken multithreaded version
// "Double-Checked Locking" idiom
class MyClass {
private MyHelper helper;
public MyHelper getHelper() {
if (helper == null) {
synchronized(this) {
if (helper == null) {
helper = new MyHelper();
}
}
}
return helper;
}
3) Static Initialization : If you have little idea about class loading sequence, you can connect to the fact that static blocks are executed during the loading of class and even before the constructor is called. We can use this feature in our singleton pattern also like this:
public class StaticBlockSingleton {
private static final StaticBlockSingleton INSTANCE;
static {
try {
INSTANCE = new StaticBlockSingleton();
} catch (Exception e) {
throw new RuntimeException(" Error!", e);
}
}
public static StaticBlockSingleton getInstance() {
return INSTANCE;
}
private StaticBlockSingleton() {
// ...
}
}
Above
code has one drawback. Suppose there are 5 static fields in class and
application code needs to access only 2 or 3, for which instance creation is
not required at all. So, if we use this static initialization. we will have one
instance created though we require it or not.
4) The
solution of Bill Pugh : Researcher Bill write the code Pugh's efforts on the "Double-checked
locking" idiom led to changes in the Java memory model
in Java 5 and to what is generally regarded as the standard method to implement
Singletons in Java. The technique known as the initialization
on demand holder idiom, is as lazy as possible, and works in
all known versions of Java. It takes advantage of language guarantees about
class initialization, and will therefore work correctly in all Java-compliant
compilers and virtual machines.
The nested class is referenced no earlier (and therefore loaded no
earlier by the class loader) than the moment that getInstance() is called.
Thus, this solution is thread-safe without requiring special language
constructs (i.e. volatile or synchronized).
public class Singleton {
private Singleton() { }
/**
* SingletonHolder is loaded on the first execution of Singleton.getInstance()
* or the first access to SingletonHolder.INSTANCE, not before.
*/
private static class SingletonHolder {
public static final Singleton INSTANCE = new Singleton();
}
public static Singleton getInstance() {
return SingletonHolder.INSTANCE;
}
}
5) Using Enum : This type of implementation recommend the use of enum. Enum, as written in java docs, provide implicit
support for thread safety and only one instance is guaranteed. This is also a
good way to have singleton with minimum effort.
public
enum Singleton {
INSTANCE;
public void execute (String arg) {
// perform operation here
}
}
This approach implements the singleton by taking
advantage of Java's guarantee that any enum value is instantiated only once in
a Java program. Since Java enum values are globally accessible, so is the singleton,
initialized lazily by the classloader. The drawback is that the enum type is
somewhat inflexible.
6) readResolve() Method : If the Singleton class implements the
java.io.Serializable interface, when a singleton is serialized and then deserialized more than once, there will be
multiple instances of Singleton
created. In order to avoid this the readResolve method should be implemented
public class Singleton implements Serializable {
// This method is called immediately after an
//object of this class is deserialized.
// This method returns the singleton instance.
protected Object readResolve() {
return getInstance();
}
}
// This method is called immediately after an
//object of this class is deserialized.
// This method returns the singleton instance.
protected Object readResolve() {
return getInstance();
}
}
Let’s say your application is distributed and it
frequently serialize the objects in file system, only to read them later when
required. Please note that, de-serialization always creates a new instance.
Lets understand using an example
Our singleton class is:
public class DemoSingleton implements Serializable {
private volatile static DemoSingleton instance = null;
public static DemoSingleton getInstance() {
if (instance == null) {
instance = new DemoSingleton();
}
return instance;
}
private int i = 10;
public int getI() {
return i;
}
public void setI(int i) {
this.i = i;
}
}
It
will give output as below
20
10
To solve this issue, we need to include readResolve() method in our DemoSingleton
class. This method will be invoked when you will de-serialize the object.
Inside this method, you must return the existing instance to ensure single
instance application wide.
Intuitively,this algorithm seems like an efficient solution to the problem. However, this
technique has many subtle problems and should usually be avoided. For example,
consider the following sequence of events:
public class DemoSingleton implements Serializable {
private volatile static DemoSingleton instance = null;
public static DemoSingleton getInstance() {
if (instance == null) {
instance = new DemoSingleton();
}
return instance;
}
protected Object readResolve() {
return instance;
}
private int i = 10;
public int getI() {
return i;
}
public void setI(int i) {
this.i = i;
}
}
It will give output as below
20
20
Notes
about double-checked locking :
Notes
about double-checked locking :
It is typically used to reduce locking overhead when implementing "lazy initialization" in a multi-threaded
environment,
1)
Thread
A notices that the value is not initialized, so it obtains the lock and begins
to initialize the value.
2)
Due
to the semantics of some programming languages, the code generated by the
compiler is allowed to update the shared variable to point to a partially
constructed object before A has finished performing the initialization. For
example, in Java if a call to a constructor has been inlined then the shared
variable may immediately be updated once the storage has been allocated but
before the inlined constructor initializes the object
3)
Thread
B notices that the shared variable has been initialized (or so it appears), and
returns its value. Because thread B believes the value is already initialized,
it does not acquire the lock. If B uses the object before all of the
initialization done by A is seen by B (either because A has not finished
initializing it or because some of the initialized values in the object have
not yet percolated to the memory B uses (cache
coherence)), the
program will likely crash.
One of the dangers of using double-checked locking in J2SE 1.4 (and earlier versions) is
that it will often appear to work: it is not easy to distinguish between a
correct implementation of the technique and one that has
subtle problems .
As of J2SE 5.0, this problem has been
fixed. The volatile keyword now ensures that multiple
threads handle the singleton instance correctly
// Works with acquire/release semantics for volatile
// Broken under Java 1.4 and earlier semantics for
volatile
class
Foo {
private volatile Helper helper;
public Helper getHelper() {
Helper result = helper;
if (result == null) {
synchronized(this) {
result = helper;
if (result == null) {
helper = result = new Helper();
}
}
}
return result;
}
}
Note the local variable result,
which seems unnecessary. This ensures that in cases where helper is
already initialized (i.e., most of the time), the volatile field is only accessed
once, which can improve the method's overall performance by as much as 25
percent
// Correct lazy initialization in Java
@ThreadSafe
class Foo {
private static class HelperHolder {
public static Helper helper = new Helper();
}
public static Helper getHelper() {
return HelperHolder.helper;
}
}
This relies on the fact that inner classes
are not loaded until they are referenced. Semantics of final field in Java 5 can
be employed to safely publish the helper object without using volatile
public class FinalWrapper<T> {
public final T value;
public FinalWrapper(T value) {
this.value = value;
}
}
public class Foo {
private FinalWrapper<Helper> helperWrapper;
public Helper getHelper() {
FinalWrapper<Helper> wrapper = helperWrapper;
if (wrapper == null) {
synchronized(this) {
if (helperWrapper == null) {
helperWrapper = new FinalWrapper<Helper>(new Helper());
}
wrapper = helperWrapper;
}
}
return wrapper.value;
}
}
The local variable wrapper is required for correctness. Performance of this implementation is not necessarily
better than the volatile implementation.
No comments:
Post a Comment