The singleton design pattern is one of the creational patterns. “The Singleton Design Pattern will ensure that there is only one instance of a class”. The term came from the mathematical concept of a singleton. In mathematics, a singleton, also known as a unit set,[1] is a set with exactly one element. The class diagram of the Singleton is given below.
The below design elements need to consider when we are developing the singleton class. The Singleton class will contain,
- Static Member – This contains the instance of the singleton class.
- Private Constructor – This will prevent anybody else to instantiate the Singleton class.
- Static Public Method – This provides the global point of access to the Singleton object and returns the instance to the client calling class.
Now, we will see the implementation of the singleton design pattern.
Singleton with lazy initialization:
The example implementation is going to use lazy initialization.
package org.smarttechie; public class SingletonLazyInitialization { private static SingletonLazyInitialization singletonInstance; private SingletonLazyInitialization() { System.out.println("==Instance created=="); } // Providing Global point of access public static SingletonLazyInitialization getSingletonInstance() { if (null == singletonInstance) { try Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } singletonInstance = new SingletonLazyInitialization(); } System.out.println("==Get instance called =="); return singletonInstance; } }
The explanation is given below.
We will test the above code with the client code.
package org.smarttechie; public class SingletonLazyInitializationTest { public static void main(String[] args) { SingletonLazyInitialization.getSingletonInstance(); SingletonLazyInitialization.getSingletonInstance(); SingletonLazyInitialization.getSingletonInstance(); SingletonLazyInitialization.getSingletonInstance(); } }
The output of the code is given below.
==Instance created== ==Get instance called == ==Get instance called == ==Get instance called == ==Get instance called ==
The output is telling there is only one object has been created when we call getSingletonInstance() method the first time. For the subsequent calls, the created object reference has been returned.
We will test the same SingletonLazyInitialization class with the multi-threaded environment. The thread class code is given below.
package org.smarttechie; public class SampleThread implements Runnable { @Override public void run() { SingletonLazyInitialization.getSingletonInstance(); } }
We will launch multiple threads to test the SingletonLazyInitialization class. The client code is provided below.
package org.smarttechie; public class SingletonLazyInitializationTest { public static void main(String[] args) { SampleThread s1 = new SampleThread(); SampleThread s2 = new SampleThread(); Thread t = new Thread(s1); Thread u = new Thread(s2); t.start(); u.start(); } }
The output of the above code is given below.
==Instance created== ==Instance created== ==Get instance called == ==Get instance called ==
From the output, we can observe that the constructor called twice and two instances have been created. So, in a multi-threaded environment, the SingletonLazyInitialization won’t work.
The advantages of the above implementation are “Faster, because of lazy initialization. Works well in the single-threaded environment”.
The disadvantages of the above implementation are “It will give abrupt behavior in a multi-threaded environment. Possibly create multiple instances”.
Singleton with double check locking:
The singleton with lazy initialization will not assure that there is only one instance in the multi-threaded environment. To make singleton to work in a multi-threaded environment, we need to use some lock so that the subsequent threads won’t get into “getSingletonInstance()” method.
The implementation is given below.
package org.smarttechie; public class SingletonDoubleCheckLock { private static SingletonDoubleCheckLock singletonInstance; private SingletonDoubleCheckLock() { System.out.println("==Instance created=="); } // Providing Global point of access public static SingletonDoubleCheckLock getSingletonInstance() { if (null == singletonInstance) { try { Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } synchronized (SingletonDoubleCheckLock.class){ if (null == singletonInstance) { singletonInstance = new SingletonDoubleCheckLock(); } } } System.out.println("==Get instance called =="); return singletonInstance; } }
The explanation is given below.
We will test the above implementation in a multi-threaded environment. The client code is given below.
package org.smarttechie; public class SingletonDoubleCheckLockTest { public static void main(String[] args) { SampleThreadDoubleCheckLock s1 = new SampleThreadDoubleCheckLock(); SampleThreadDoubleCheckLock s2 = new SampleThreadDoubleCheckLock(); Thread t = new Thread(s1); Thread u = new Thread(s2); t.start(); u.start(); } }
The output is given below.
==Instance created== ==Get instance called == ==Get instance called ==
From the above output, we can conclude that double check lock ensures that, at any point, the only a single instance will get created.
Singleton with early initialization:
This is the third way of implementing a singleton. The code is given below.
package org.smarttechie; public class SingletonEarlyInitialization { private static SingletonEarlyInitialization singletonInstance = new SingletonEarlyInitialization(); private SingletonEarlyInitialization() { System.out.println("==Instance created=="); } // Providing Global point of access public static SingletonEarlyInitialization getSingletonInstance() { System.out.println("==Get instance called =="); return singletonInstance; } }
The explanation is given below.
In the above code, the static variable gets initialized during the class loading. The instance is created before accessing by threads. That ensures that, in a multi-threaded environment, there is only a single instance is available. The example code used in this article is available here.
Happy learning !!!
Truly informative.
Cheers!
Singleton design pattern explained very clearly with examples. Thanks for that and would love to see more topics from you
Thank you Siva.