Tuesday 12 November 2013

Singleton Design Pattern in Java

Singleton Class:
The implementation of a Singleton class enforces, there must be a maximum of only one object of its type at any given time. Also Singleton class will make sure that its object won’t be garbage collected during the application running.

First of all to construct a Singleton object, programmer should aware of in how many ways an object can be created. So that can take precautions to make sure that the class following Singleton Design Pattern.

1. Possible ways to create an Object:
1.1. By using new keyword. This is the most commonly used approach in java.
SingletonObject object = new SingletonObject();

1.2. By using Class.forName(). It can be possible if the class has public default constructor.
SingletonObject object = (SingletonObject) Class.forName("com.edu.SingletonObject").newInstance();

1.3. By using the clone() method we can create a copy of an existing object.
SingletonObject object = new SingletonObject();
SingletonObject anotherObj = object.clone();

1.4. By using the Object deserialization, can able to create an object from its serialized form.
ObjectInputStream inStream = new ObjectInputStream(inputStream );
SingletonObject object = (SingletonObject) inStream.readObject();

2. Construction of Singleton Object by preventing above possibilities:
2.1. Use a private constructor, hence we cannot create an object of a class outside of it’s by using new keyword. This also prevents creation of an object from Class.forName(). Will get the flowing exception at run time.
private SingletonObject() {}

2.2. To prevents from cloning, simple write a clone() method in Singleton java file and throw an exception saying that cloning is not supported.
public Object clone() throws CloneNotSupportedException {
 throw new CloneNotSupportedException();
} 

2.3. To prevent from de-serialization process, implement Serialization interface and provide the body for both methods readObject() and readResolve() in such a way that it should provide the same current object. The total implementation of a Singleton Java class as follows:
package com.edu;

import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectStreamException;
import java.lang.reflect.Constructor;
import java.io.Serializable;

public class SingletonObject implements Serializable {
 
 /**
  * 
  */
 private static final long serialVersionUID = 1L;
 
 private static SingletonObject singletonObject;
 public static int x;
 
 private SingletonObject() { }
 
 public static synchronized SingletonObject getInstance() {
  if (singletonObject == null) {
   singletonObject = new SingletonObject();
   singletonObject.x = x + 10;;
  }
  return singletonObject;
 }
 
 private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException {
  ois.defaultReadObject();
  synchronized (SingletonObject.class) {
   if (singletonObject == null) {
    singletonObject = this; // only if everything succeeds
   }
  }
 }
 
 private Object readResolve() throws ObjectStreamException {
        if(singletonObject != null);
        return singletonObject;
    }
 
 
  
 public Object clone() throws CloneNotSupportedException {
  throw new CloneNotSupportedException();
 }
}

3. Why synchronized keyword used for getInstance() method:
Since the singleton instance is a static class variable in the stored in the PermGen space of the heap. This applies getInstance() instance method as well since it is static too. In the multithreading environment to prevent each thread to create another instance of singleton object and thus creating concurrency issue we will need to use locking mechanism. This can be achieved by synchronized keyword. By using this synchronized keyword we prevent Thread2 or Thread3 to access the singleton instance while Thread1 inside the method getInstance().

Client Code:
package com.edu;

import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.InvocationTargetException;

public class SingletonTest {
 
 public static void main(String[] args) throws SecurityException, NoSuchMethodException, 
  IllegalArgumentException, InvocationTargetException, CloneNotSupportedException {
  try {
   
   //1. TO test for new keyword
   /*
   SingletonObject obj1 = new SingletonObject();
   */
   
   //2. To test Class.forName()
   /*
   SingletonObject obj = (SingletonObject)Class.forName("com.edu.SingletonObject").newInstance();
   System.out.println(obj.getInstance().x);
   */
   
   //3. To test Reflection
   /*
   Class<SingletonObject> obj = (Class<SingletonObject>) Class.forName("com.edu.SingletonObject");
   Constructor<SingletonObject> constructor = obj.getDeclaredConstructor();
   SingletonObject obj1 = constructor.newInstance("SingletonObject");
   SingletonObject object = obj1.getInstance();
   */
   
   
   //4. To test cloning
   /*
   SingletonObject obj = SingletonObject.getInstance();
   obj.clone();
   System.out.println(obj.x);
   */
   
   
   //5. To test object de-serialization
   ByteArrayOutputStream baos = new ByteArrayOutputStream();
            ObjectOutputStream oos = new ObjectOutputStream(baos);
            oos.writeObject(SingletonObject.getInstance());
            oos.close();

            java.io.InputStream is = new java.io.ByteArrayInputStream(baos.toByteArray());
            ObjectInputStream ois = new ObjectInputStream(is);
            SingletonObject singletonObject = (SingletonObject)ois.readObject();
            
            System.out.println(singletonObject.x);
   
  } catch(Exception e) {
   e.printStackTrace();
  }
 }
}

Test Results:
Enable either one option in the test program and run one by one.
1. Will get compilation error.
Error: The constructor SingletonObject() is not visible.
2. Will get Runtime error.
Error:
java.lang.IllegalAccessException: Class com.edu.SingletonTest can not access a member of class com.edu.SingletonObject with modifiers "private"
 at sun.reflect.Reflection.ensureMemberAccess(Reflection.java:65)
 at java.lang.Class.newInstance0(Class.java:351)
 at java.lang.Class.newInstance(Class.java:310)
 at com.edu.SingletonTest.main(SingletonTest.java:21)

3. Will get runtime error:
Error:
java.lang.IllegalAccessException: Class com.edu.SingletonTest can not access a member of class com.edu.SingletonObject with modifiers "private"
 at sun.reflect.Reflection.ensureMemberAccess(Reflection.java:65)
 at java.lang.reflect.Constructor.newInstance(Constructor.java:505)
 at com.edu.SingletonTest.main(SingletonTest.java:30)

4. Since we have provided the method implementation for this scenario in such a way that to provide the same copy of an object. It will provide the same.

When to use Singleton Design Pattern:
Any class which you want to be available to whole application and whole only one instance is viable is candidate of becoming Singleton. One example of this is Runtime class , since on whole java application only one runtime environment can be possible making Runtime Singleton is right decision. Another example is a utility classes like Popup in GUI application, if you want to show popup with message you can have one PopUp class on whole GUI application and anytime just get its instance, and call show() with message.

Uses of Singleton Design Pattern:
DB Connection: We can create a Database connection once and can provide a global point of reference.
Configuration File: It creates a single instance of the configuration file which can be accessed by multiple calls concurrently as it will provide static config data loaded into in-memory objects. The application only reads from the configuration file at the first time and thereafter from second call onwards the client applications read the data from in-memory objects.
Cache: We can use the cache as a singleton object as it can have a global point of reference and for all future calls to the cache object the client application will use the in-memory object.

No comments:

Post a Comment