Java Design Pattern Examples - Singleton Design Pattern



Singleton pattern restricts the instantiation of a class and guarantees that only one instance of the class exists in the JVM. The singleton class must provide a global access point to get the instance of the class. 


It is possible to have different approaches while implementing Singleton pattern but there are some requirements that all Singleton classes must obey. These are:

  • Private constructor (Restricts 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(The global access point for outer world to get the instance of the singleton class.)

Throughout this post, we will introduce these different approaches of Singleton pattern implementation and design concerns with their respective implementation.

Eager Initialization

In eager initialization, the Singleton instance is created at the time when the class is loaded. This is the simplest way of creating a singleton class, however it is a waste of resources if the created instance might not be used.

/**
 * SingleObject.java - A Singleton Class
 * 
 */
public class SingleObject {
 // create an object of SingleObject
 private static SingleObject instance = new SingleObject();

 // private constructor (cannot be initialized)
 private SingleObject() {}

 // returns the created object on method call
 public static SingleObject getInstance() {
  return instance;
 }

 public void print() {
  System.out.println("I am a Singleton!");
 }
 
}


/**
 * Main Class to Test the Functionality
 *
 */
public class Main {
 public static void main(String[] args) {
  SingleObject singleton = SingleObject.getInstance(); 
  singleton.print();
 }
}

As the result we get "I am a Singleton!". Now let's have a look at a lazier way of doing this:

Lazy Initialization

Lazy initialization creates the instance in the global access method only if the instance is null. If another thread already created an instance, then it will not recreate it. Here is the sample code for creating Singleton class with this approach.


/**
 * Lazy Initialization - Another Singleton Class
 * 
 */
public class LazyInit {
 // define but don't initalize
 private static LazyInit instance;

 private LazyInit() {}

 public static LazyInit getInstance() {
  // if this is a null instance; create, otherwise don't
  if (instance == null) {
   instance = new LazyInit();
  }
  return instance;
 }

 public void print() {
  System.out.println("I am a Lazy Singleton!");
 }
}


/**
 * Main Class to Test the Functionality
 *
 */
public class Main {
 public static void main(String[] args) {
  LazyInit lazy = LazyInit.getInstance();
  lazy.print();
 }
}

The above implementation works fine if the environment has just a single thread. Otherwise, if there are multiple threads using our Singleton class, it is very likely to have multiple instances running around. The reason for this is that two threads can potentially access the getInstance() method at the same time and request instances. We do not want this to happen if we are working on a multi-threaded environment. In the following section, we will see how we can create a thread-safe singleton class.

Thread Safe Singleton

The easiest way to create a thread-safe singleton class is to make the global access method synchronized, so that only one thread can execute this method at a time. Here is an example;

/**
 * Thread Safe Singleton Example
 * 
 */
public class ThreadSafeSingleton {

 private static ThreadSafeSingleton instance;

 private ThreadSafeSingleton() {}

 public static synchronized ThreadSafeSingleton getInstance() {
  if (instance == null) {
   instance = new ThreadSafeSingleton();
  }
  return instance;
 }

 public void print(String s) {
  System.out.println(s + " is using \n" + instance);
 }
}

Since we have a thread safe singleton class, let's test it out shall we?

/**
 * Demo Class implements Runnable
 *
 */
public class Demo implements Runnable {
 private Thread t;
 private String name;
 private ThreadSafeSingleton singleton;

 public Demo(String name) {
  this.name = name;
 }

 public void start() {
  if (t == null) {
   t = new Thread(this, name);
   t.start();
  }
 }

 @Override
 public void run() {
  singleton = ThreadSafeSingleton.getInstance();
  singleton.print(name);
 }
}

In the above class, we implement the Runnable interface to be able to create our threads. We are also using this class to get the singleton instance and print the names of the threads by using this single instance. Here is the main class to test the functionality:

public class Main {
 public static void main(String[] args) {
  Demo d1 = new Demo("Thread 1");
  d1.start();
  Demo d2 = new Demo("Thread 2");
  d2.start();
  Demo d3 = new Demo("Thread 3");
  d3.start();
  Demo d4 = new Demo("Thread 4");
  d4.start();
 }
}

The output is as follows:

Thread 4 is using 
codemio.ThreadSafeSingleton@578bcb67
Thread 2 is using 
codemio.ThreadSafeSingleton@578bcb67
Thread 1 is using 
codemio.ThreadSafeSingleton@578bcb67
Thread 3 is using 
codemio.ThreadSafeSingleton@578bcb67

As you can see all four of our threads are using the same instance. If you would like to see what happens when you don't use a thread safe singleton class, here is the answer:

Thread 3 is using 
codemio.ThreadUnsafeSingleton@45a19d0b
Thread 1 is using 
codemio.ThreadUnsafeSingleton@634cfa19
Thread 2 is using 
codemio.ThreadUnsafeSingleton@45a19d0b
Thread 4 is using 
codemio.ThreadUnsafeSingleton@ee2658c

Using synchronized methods to provide thread safety works fine but there is a better way that avoids the cost associated with the synchronized method. This approach is called Double Checked Locking (DCL).

Thread Safety using Double Checked Locking

If we add the following method to ThreadSafeSingleton Class and use it to get instances, we can obtain better results in terms of performance than the previous example. Please note that, the instance is now defined as volatile Volatile variable in Java is a special variable which is used to signal threads, a compiler that this particular variables value are going to be updated by multiple threads inside Java application. 

By making a variable volatile using the volatile keyword in Java, programmer ensures that its value should always be read from the main memory and thread should not use cached value of that variable from their own stack. 

In the old days, before Java 5, there was a discussion about Double Checked Locking and it was considered as broken. However in today's Java 8, the implementation of volatile has changed and therefore if we use volatile, we are safe to use DCL to obtain thread safety. Here is the code for this approach:

/**
 * Thread Safe Singleton - Double Checked Locking Example
 * 
 */
public class ThreadSafeSingleton {

 private static volatile ThreadSafeSingleton instance;

 private ThreadSafeSingleton() {}

 public static ThreadSafeSingleton getInstanceUsingDoubleLocking(){
     if(instance == null){
         synchronized (ThreadSafeSingleton.class) {
             if(instance == null){
                 instance = new ThreadSafeSingleton();
             }
         }
     }
     return instance;
 }
 public void print(String s) {
  System.out.println(s + " is using \n" + instance);
 }
}


Lastly, you should know that Singleton Pattern lately seems orphaned by the developer world since a lot of people think that they cause problems. I would like to give you some links to read on this topic.

What is so bad about singletons?

Why Singletons are Evil

The Good, the Bad and the Singleton - Big ball of mud

Alright, that's all for this post. Please check out the upcoming Design Patterns Tutorial with Examples Using Java post for all the design patterns. Happy coding!
Author:

Software Developer, Codemio Admin


Disqus Comments Loading..