Java Singleton Design Pattern Practices with Examples

In previous articles, we discussed about singleton design pattern and singleton class implementation in detail.
In this article, we will see how we can create singleton classes. After reading this article you will be able to create your singleton class according to your use, simplicity and removed bottlenecks.
There are many ways this can be done in Java. All these ways differs in their implementation of the pattern, but in the end, they all achieve the same end result of a single instance.

  1. Eager initialization: This is the simplest method of creating a singleton class. In this, object of class is created when it is loaded to the memory by JVM. It is done by assigning the reference an instance directly.
    It can be used when program will always use instance of this class, or the cost of creating the instance is not too large in terms of resources and time.

    // Java code to create singleton class by 
    // Eager Initialization
    public class GFG 
    {
      // public instance initialized when loading the class
      public static GFG instance = new GFG();
    
      private GFG()
      {
        // private constructor
      }
    }
    

    Pros:

    1. Very simple to implement.
    2. No need to implement getInstance() method. Instance can be accessed directly.

    Cons:

    1. May lead to resource wastage. Because instance of class is created always, whether it is required or not.
    2. CPU time is also wasted in creation of instance if it is not required.
    3. Exception handling is not possible.
  2. Using static block: This is also a sub part of Eager initialization. The only difference is object is created in a static block so that we can have access on its creation, like exception handling. In this way also, object is created at the time of class loading.
    It can be used when there is a chance of exceptions in creating object with eager initialization.

    // Java code to create singleton class
    // Using Static block
    public class GFG 
    {
      // public instance
      public static GFG instance;
    
      private GFG() 
      {
        // private constructor
      }
    
      {
        // static block to initialize instance
        instance = new GFG();
      }
    }
    

    Pros:

    1. Very simple to implement.
    2. No need to implement getInstance() method. Instance can be accessed directly.
    3. Exceptions can be handled in static block.

    Cons:

    1. May lead to resource wastage. Because instance of class is created always, whether it is required or not.
    2. CPU time is also wasted in creation of instance if it is not required.
  3. Lazy initialization: In this method, object is created only if it is needed. This may prevent resource wastage. An implementation of getInstance() method is required which return the instance. There is a null check that if object is not created then create, otherwise return previously created. To make sure that class cannot be instantiated in any other way, constructor is made final. As object is created with in a method, it ensures that object will not be created until and unless it is required. Instance is kept private so that no one can access it directly.
    It can be used in a single threaded environment because multiple threads can break singleton property because they can access get instance method simultaneously and create multiple objects.

    //Java Code to create singleton class
    // With Lazy initialization
    public class GFG 
    {
      // private instance, so that it can be
      // accessed by only by getInstance() method
      private static GFG instance;
    
      private GFG() 
      {
        // private constructor
      }
    
      //method to return instance of class
      public static GFG getInstance() 
      {
        if (instance == null) 
        {
          // if instance is null, initialize
          instance = new GFG();
        }
        return instance;
      }
    }
    

    Pros:

    1. Object is created only if it is needed. It may overcome resource overcome and wastage of CPU time.
    2. Exception handling is also possible in method.

    Cons:

    1. Every time a condition of null has to be checked.
    2. instance can’t be accessed directly.
    3. In multithreaded environment, it may break singleton property.
  4. Thread Safe Singleton: A thread safe singleton in created so that singleton property is maintained even in multithreaded environment. To make a singleton class thread-safe, getInstance() method is made synchronized so that multiple threads can’t access it simultaneously.
    // Java program to create Thread Safe
    // Singleton class
    public class GFG 
    {
      // private instance, so that it can be
      // accessed by only by getInstance() method
      private static GFG instance;
    
      private GFG() 
      {
        // private constructor
      }
    
     //synchronized method to control simultaneous access
      synchronized public static GFG getInstance() 
      {
        if (instance == null) 
        {
          // if instance is null, initialize
          instance = new GFG();
        }
        return instance;
      }
    }
    

    Pros:

    1. Lazy initialization is possible.
    2. It is also thread safe.

    Cons:

    1. getInstance() method is synchronized so it causes slow performance as multiple threads can’t access it simultaneously.
  5. Lazy initialization with Double check locking: In this mechanism, we overcome the overhead problem of synchronized code. In this method, getInstance is not synchronized but the block which creates instance is synchronized so that minimum number of threads have to wait and that’s only for first time.
    // Java code to explain double check locking
    public class GFG 
    {
      // private instance, so that it can be
      // accessed by only by getInstance() method
      private static GFG instance;
    
      private GFG() 
      {
        // private constructor
      }
    
      public static GFG getInstance()
      {
        if (instance == null) 
        {
          //synchronized block to remove overhead
          synchronized (GFG.class)
          {
            if(instance==null)
            {
              // if instance is null, initialize
              instance = new GFG();
            }
          
          }
        }
        return instance;
      }
    }
    

    Pros:

    1. Lazy initialization is possible.
    2. It is also thread safe.
    3. Performance reduced because of synchronized keyword is overcome.

    Cons:

    1. First time, it can affect performance.

    As cons. of double check locking method is bearable so it can be used for high performance multi-threaded applications.

  6. Bill Pugh Singleton Implementation: Prior to Java5, memory model had a lot of issues and above methods caused failure in certain scenarios in multithreaded environment. So, Bill Pugh suggested a concept of inner static classes to use for singleton.
    // Java code for Bill Pugh Singleton Implementaion
    public class GFG 
    {
    
      private GFG() 
      {
        // private constructor
      }
    
      // Inner class to provide instance of class
      private static class BillPughSingleton
      {
        private static final GFG INSTANCE = new GFG();
      }
    
      public static GFG getInstance() 
      {
        return BillPughSingleton.INSTANCE;
      }
    }
    

    When the singleton class is loaded, inner class is not loaded and hence doesn’t create object when loading the class. Inner class is created only when getInstance() method is called. So it may seem like eager initialization but it is lazy initialization.
    This is the most widely used approach as it doesn’t use synchronization.

When to use What

  1. Eager initialization is easy to implement but it may cause resource and CPU time wastage. Use it only if cost of initializing a class is less in terms of resources or your program will always need the instance of class.
  2. By using Static block in Eager initialization we can provide exception handling and also can control over instance.
  3. Using synchronized we can create singleton class in multi-threading environment also but it can cause slow performance, so we can use Double check locking mechanism.
  4. Bill Pugh implementation is most widely used approach for singleton classes. Most developers prefer it because of its simplicity and advantages.

This article is contributed by Vishal Garg. If you like GeeksforGeeks and would like to contribute, you can also write an article using contribute.geeksforgeeks.org or mail your article to contribute@geeksforgeeks.org. See your article appearing on the GeeksforGeeks main page and help other Geeks.

Please write comments if you find anything incorrect, or you want to share more information about the topic discussed above.




Please write to us at contribute@geeksforgeeks.org to report any issue with the above content.

Recommended Posts:



3.5 Average Difficulty : 3.5/5.0
Based on 2 vote(s)