Creating Singleton Class in Java without using any Framework

In this Programming article I will discuss what is Singleton Design pattern. I will also show you how to create a Singleton class in Java without using any framework like Spring.

What is Singleton

Singleton is a design pattern which is frequently implemented to consciously avoid creation of multiple objects of a single class. A class implementing Singleton design pattern, is often referred as Singleton class. Only one object is created per container from a Singleton class. The only object created from a Singleton class is called Singleton object.

 
 

When to use Singleton

As the definition suggests, only one object exists per Singleton class. Thus you essentially loose safety while using Singleton object in a multi-threaded environment. Great care must be taken while implementing a Singleton class or using a Singleton object. For example, a developer must avoid using a class level property (variable) in a singleton class which is being read and updated by one or more methods in the class. Since only one object is created from Singleton class and the object is re-used across threads, it’s best to avoid a class level property to ensure that the operations remain thread safe and do not interfere with each-other.

Singleton is the choice of developers when there is a need to optimize memory utilization. For example, if you have a service layer in your application, which is responsible for passing on the control/request from Servlets to the Data Access layer after doing minor business operations. You often choose Singleton design pattern for classes present in Service layers. These classes contains service methods (and no class level variable). These methods are modular in nature and serves specific purpose. Eg. UserService.getUserDetailsById(long userId) would only be used to return details of user when userid is given as parameter.

Singleton is also useful when it is intentionally expected to establish single-threaded processing. For example, if you want serial access to a hardware resource like Printer. You might find Singleton the most effective design pattern in this case. Further discussion on this scenario is not in scope of this blog.

How to create Singleton Class and Singleton Object in Java

See the diagram below, demonstrating the basic internal structure of a Singleton Class.

Singleton Class Structure

Now, I will share the code snippet of the Single class. Only one object can be created from this class. The class would also ensure that a duplicate object can’t be created by cloning or deserializing the object.


package com.sribasu.java;

import java.io.Serializable;

/**
 * This is a singleton class. This class doesn't implement Cloneable interface
 * which ensure than cloning object of this class is not allowed.
 * 
 * @author Prithwiraj Bose
 *
 */
public class SingletonExample implements Serializable, Cloneable {
	private String exampleProperty;

	/**
	 * By making the constructor private, we prevent any other class to create
	 * an instance of SingletonExample class using new keyword
	 */
	private SingletonExample() {

	}

	/**
	 * Static Factory method of SingletonExample class
	 * 
	 * @return singleton instance of SingletonExample
	 */
	public static synchronized SingletonExample getInstance() {
		return SingletonExampleInstanceContainer.instance;
	}

	public String getExampleProperty() {
		return exampleProperty;
	}

	public void setExampleProperty(String exampleProperty) {
		this.exampleProperty = exampleProperty;
	}

	/**
	 * clone() method ensures that cloning is allowed but the clone is also a
	 * reference of the Singleton object only and not a new instance
	 * 
	 * @return singleton instance of SingletonExample
	 */
	protected Object clone() {
		return SingletonExampleInstanceContainer.instance;
	}

	/**
	 * This method ensures that the same singleton reference is returned when
	 * the object is serialized and the deserialized back
	 * 
	 * @return singleton instance of SingletonExample
	 */
	protected Object readResolve() {
		return SingletonExampleInstanceContainer.instance;
	}

	/**
	 * Private static instance holder. This is early loading example, where the
	 * singleton instance is initialized during class loading.
	 * 
	 * @author a07752a
	 *
	 */
	private static final class SingletonExampleInstanceContainer {
		static final SingletonExample instance = new SingletonExample();
	}

}

In the following class I have shown how to test if the above class is really a Singleton Class or not. For that I will try to create more than one object of the class using every possible way.


package com.sribasu.java;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;

public class SingletonTest {
	public static void main(String[] args) {
		/** Get the initial object from the static factory **/
		SingletonExample singletonExampleObj = SingletonExample.getInstance();
		System.out.println(singletonExampleObj.hashCode());

		/** Reinvoke the factory method to see if a new instance is returned **/
		singletonExampleObj = SingletonExample.getInstance();
		System.out.println(singletonExampleObj.hashCode());

		/**
		 * Check if duplicate instance can be created with Dynamic Class loading
		 * Since the class has a public constructor, it is evident that Dynamic
		 * Class loading would fail with IllegalAccessException
		 */
		try {
			singletonExampleObj = (SingletonExample) Class.forName("com.sribasu.java.SingletonExample").newInstance();
			System.out.println(singletonExampleObj.hashCode());
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

		/**
		 * Check if object cloning make a duplicate instance creation possible
		 * or not
		 */
		singletonExampleObj = (SingletonExample) singletonExampleObj.clone();
		System.out.println(singletonExampleObj.hashCode());

		/**
		 * Finally check if serializing and deserializing consecutively results
		 * in a duplicate object or not
		 */
		FileOutputStream fileOp = null;
		ObjectOutputStream out = null;
		File f = new File("serializedData.dat");
		try {
			if (!f.exists())
				f.createNewFile();
			fileOp = new FileOutputStream(f);
			out = new ObjectOutputStream(fileOp);

			// Method for serialization of object
			out.writeObject(singletonExampleObj);
		} catch (Exception ex) {
			ex.printStackTrace();
		} finally {
			try {
				out.close();
				fileOp.close();
			} catch (Exception e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}

		FileInputStream fileIp = null;
		ObjectInputStream in = null;
		try {
			fileIp = new FileInputStream(f);
			in = new ObjectInputStream(fileIp);

			singletonExampleObj = (SingletonExample) in.readObject();
		} catch (Exception ex) {
			ex.printStackTrace();
		} finally {
			try {
				in.close();
				fileIp.close();
			} catch (Exception e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		System.out.println(singletonExampleObj.hashCode());

	}
}

Output of the above program is:

1704856573
1704856573
java.lang.IllegalAccessException: Class com.sribasu.java.SingletonTest can not access a member of class com.sribasu.java.SingletonExample with modifiers "private" at sun.reflect.Reflection.ensureMemberAccess(Reflection.java:102) at java.lang.Class.newInstance(Class.java:436) at com.sribasu.java.SingletonTest.main(SingletonTest.java:19)
1704856573 1704856573

At the end, I must say Singleton is a concept which limits to the boundary we define. In the above example, the defined boundary is Per Classloader. You can very well introduce multiple classloaders and thus create multiple objects of the Singleton class. There are number of ways to make this Singleton class stricter by preventing multiple classloaders to create more than one object. I will write a separate blog if possible, on that topic. Please let me know if this tutorial helped you understand Singleton design pattern better, in the comments section.

Please follow and like us:
Pin Share

Leave a Reply

Your email address will not be published. Required fields are marked *