Singleton pattern restricts the instantiation of a class and ensures that only one instance of the class exists in the Application. The singleton class must provide a global access point to get the instance of the class.
Approach for Singleton:
- Private constructor to restrict instantiation of the class from other classes.
- Private static variable of the same class that is the only instance of the class.
- Public static method that returns the instance of the class, this is the global access point for outer world to get the instance of the singleton class.
Bellow are the different approaches of Singleton pattern implementation and design concerns with the implementation.
Eager initialization
Static block initialization
Lazy Initialization
Thread Safe Singleton
Bill Pugh Singleton Implementation
Using Reflection to destroy Singleton Pattern
Enum Singleton
Serialization and Singleton
----------------------------------------------------------------------------------------------------------
package com.test;
public class SingletonClone implements Cloneable {
@Override
protected Object clone() throws CloneNotSupportedException {
// TODO Auto-generated method stub
return super.clone();
}
}
----------------------------------------------------------------------------------------------------------
package com.test;
import java.io.Serializable;
public class JavaSingleton extends SingletonClone implements Serializable{
/**
*
*/
private JavaSingleton() {
if (javaSingleton != null) {
throw new IllegalStateException("Inside JavaSingleton(): JavaSingleton " +
"instance already created.");
}
}
@Override
protected Object clone() throws CloneNotSupportedException {
// TODO Auto-generated method stub
throw new CloneNotSupportedException();
}
private static JavaSingleton javaSingleton = null;
protected Object readResolve()
{
return javaSingleton;
}
public static JavaSingleton getInstance(){
if(javaSingleton==null){
synchronized (JavaSingleton.class) {
if(javaSingleton==null){
javaSingleton = new JavaSingleton();
System.out.println("object creation "+Thread.currentThread().getName()+javaSingleton);
}
}
}
return javaSingleton;
}
}
------------------------------------------------------------------------------------------------------------
package com.test;
public class TestMultiThreadingSingleton implements Runnable {
@Override
public void run() {
JavaSingleton javaSingleton = JavaSingleton.getInstance();
try {
JavaSingleton javaSingleton1 = (JavaSingleton) javaSingleton.clone();
System.out.println(Thread.currentThread().getName() + "-----" + javaSingleton +"--------------"+javaSingleton1);
} catch (Exception exception) {
// TODO: handle exception
exception.getMessage();
}
}
}
-----------------------------------------------------------------------------------------
package com.test;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInput;
import java.io.ObjectInputStream;
import java.io.ObjectOutput;
import java.io.ObjectOutputStream;
import java.lang.reflect.Constructor;
public class TestSingleton {
public static void main(String[] args) {
Thread thread = new Thread(new TestMultiThreadingSingleton(),"A");
Thread thread1 = new Thread(new TestMultiThreadingSingleton(),"B");
Thread thread2 = new Thread(new TestMultiThreadingSingleton(),"C");
Thread thread3 = new Thread(new TestMultiThreadingSingleton(),"D");
thread.start();
thread1.start();
thread2.start();
thread3.start();
EnumSingleton enumSingleton = EnumSingleton.INSTANCE;
EnumSingleton enumSingleton1 = EnumSingleton.INSTANCE;
System.out.println("desiarialize object -- enumSingleton"+enumSingleton);
System.out.println("desiarialize object -- enumSingleton1"+enumSingleton1);
try {
/* Serializable-Deserializable
JavaSingleton javaSingleton = JavaSingleton.getInstance();
ObjectOutput objectOutput = new ObjectOutputStream(new FileOutputStream("C:\\Users\\CBEC14\\Desktop\\abc.tx"));
objectOutput.writeObject(javaSingleton);
System.out.println(javaSingleton);
objectOutput.close();
ObjectInput input = new ObjectInputStream(new FileInputStream("C:\\Users\\CBEC14\\Desktop\\abc.tx"));
JavaSingleton javaSingleton2=(JavaSingleton)input.readObject();
System.out.println("desiarialize object"+javaSingleton2);*/
// Reflection test
Constructor[] constructors =
JavaSingleton.class.getDeclaredConstructors();
for (Constructor constructor : constructors)
{
// Below code will destroy the singleton pattern
constructor.setAccessible(true);
JavaSingleton instance2 = (JavaSingleton) constructor.newInstance();
System.out.println("reflection object"+instance2);
break;
}
} catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
}
}
}
---------------------------------------------------------------
package com.test;
public enum EnumSingleton {
INSTANCE
}
---------------------------------------------------------------------------