singleton
pattern restricts the instantiation of a class to one object. That is
you can't create more than one object to this class. This is useful
when exactly one object is needed to coordinate actions across the
system.
Will
see various approaches to construct singleton class and see the
problems in them. Finally finds better solution.
Approach
1
Make
the default constructor as private and create static instance inside
the class itself. Provide a static getter method to get the instance
of this class.
class SingleTon{ static SingleTon instance = new SingleTon(); private SingleTon(){ } public static SingleTon getInstance(){ return instance; } }
Constructor
for the SingleTon class has private access, so it can't be accessed
from outside. 'getInstance' method simply the instance which is
already created.
class SingleTonTest{ public static void main(String args[]){ SingleTon obj1 = SingleTon.getInstance(); SingleTon obj2 = SingleTon.getInstance(); System.out.print("Is obj1 and obj2 points to same object "); System.out.println((obj1==obj2)); } }
Output
Is obj1 and obj2 points to same object true
Problem
in Approach 1
Object
is created, even if needs or not. If this Object
is resource intensive and if your Application never used it, then it
is wastage of your resource.
Approach
2
Create
the instance when needed. While creating an instance check whether
instance already exist or not. If instance is not there, then create
one and return it, else return the existing one.
class SingleTon{ static SingleTon instance; private SingleTon(){ } public static SingleTon getInstance(){ if(instance == null){ instance = new SingleTon(); } return instance; } }
class SingleTonTest{ public static void main(String args[]){ SingleTon obj1 = SingleTon.getInstance(); SingleTon obj2 = SingleTon.getInstance(); System.out.print("Is obj1 and obj2 points to same object "); System.out.println((obj1==obj2)); } }
Output
Is obj1 and obj2 points to same object true
Problem
in Approach 2
In
a Multi threaded Environment, Above code won't work.
Lets
take a scenario, there are two threads t1 and t2 calls the
getInstance method. Lets us assume, t1 got a chance first to enter
into getInstance method, After checking for the condition(instance
== null) which is true, it swapped out, and t2 come in, now for t2
also the condition (instance == null) is true, so there are two
instances got created.
For
Example, let us update the program to support threads.
class SingleTon{ static SingleTon instance; private SingleTon(){ } public static SingleTon getInstance(){ if(instance == null){ instance = new SingleTon(); } return instance; } }
class SingleTonTest extends Thread{ SingleTon obj; public void run(){ obj = SingleTon.getInstance(); } public static void main(String args[])throws Exception{ SingleTonTest t1 = new SingleTonTest(); SingleTonTest t2 = new SingleTonTest(); t1.start(); t2.start(); t1.join(); t2.join(); System.out.print("Is t1.obj and t2.obj point to same object "); System.out.println((t1.obj==t2.obj)); } }
On
Multiple runs the output is like below.
Run
1:
Is
t1.obj and t2.obj point to same object false
Run
2:
Is
t1.obj and t2.obj point to same object false
Run
3:
Is
t1.obj and t2.obj point to same object false
Run
4:
Is
t1.obj and t2.obj point to same object true
Run
5:
Is
t1.obj and t2.obj point to same object true
Run
6:
Is
t1.obj and t2.obj point to same object false
Approach
3
To
solve the above problem, why can't we use synchronization. Looks like
a good idea. Now change the code like below.
class SingleTon{ static SingleTon instance = null; private SingleTon(){ } public static SingleTon getInstance(){ synchronized(SingleTon.class){ if(instance == null){ instance = new SingleTon(); } } return instance; } }
class SingleTonTest extends Thread{ SingleTon obj; public void run(){ obj = SingleTon.getInstance(); } public static void main(String args[])throws Exception{ SingleTonTest t1 = new SingleTonTest(); SingleTonTest t2 = new SingleTonTest(); t1.start(); t2.start(); t1.join(); t2.join(); System.out.print("Is t1.obj and t2.obj point to same object "); System.out.println((t1.obj==t2.obj)); } }
Output
Is t1.obj and t2.obj point to same object true
Problem in Approach3
Don't
you felt synchronization is a costliest process. If one thread
acquire the lock on the class SingleTon, then remaining all thread
must wait. So it is not effective solution.
Final
Solution
Use
double checked locking. First check whether the instance is null or
not, then take the lock if the instance is null, else return the
instance.
class SingleTon{ static SingleTon instance = null; private SingleTon(){ } public static SingleTon getInstance(){ if(instance == null){ synchronized(SingleTon.class){ if(instance == null){ instance = new SingleTon(); } } } return instance; } }
No comments:
Post a Comment