Wednesday 26 August 2015

Complete Singleton Pattern in Java Tutorial

I'm going to deliver a Complete Singleton Design Pattern in Java Tutorial here. 

What is  Singleton Design Pattern?

In Java, Singleton Pattern ensures that there is one and only one instance of a class is created in the JVM (Java Virtual Machine).

It is one of the Creational Design Patterns. 

Use-cases of Singleton Pattern:


  • Logging
  • Caching
  • Configuration File
  • Thread Pool
  • Connection Pool
  • Database Driver Object
It is also used with other Java SE Design Patterns:
  • Abstract Factory Pattern
  • Factory Pattern
  • Builder Pattern
  • Prototype Pattern
  • Facade Pattern

It is also used with some Java EE Design Patterns:

  • Service Locator Pattern


Singleton Pattern Class Diagram:



Singleton Pattern Approach:

  • Static instance of the singleton class.
  • Private constructor.
  • Static utility method to create and access the instance globally.


Singleton Pattern Implementation:

1. Eager Initialization Approach:


public class MySingleton {
private static final MySingleton instance = new MySingleton();
private MySingleton(){
}
public static MySingleton getInstance(){
return instance;
}

}

Drawbacks of Eager Initialization:

  • Does not support Lazy-Initialization
  • Does not support Exception Handling
  • No Thread-Safety that means cannot use in Multi-Threaded Environment.
  • Because of Eager Initialization, it creates objects without any Client request or Client does needed it.
  • Unnecessary waste of memory for unwanted objects.
  • Breakage by Serialization
  • Breakage by Cloning
  • Breakage by Java Reflection

2. Lazy Initialization Approach:

public class MySingleton {
private static final MySingleton instance = null;
private MySingleton(){
}
public static MySingleton getInstance(){
                if( instance == null){
                       instance = new MySingleton();
                }
return instance;
}

}

Advantages of Lazy Initialization:

  • Supports Lazy-Initialization
  • Support Exception Handling
  • It creates objects on demand from Clients
  • No wastage of memory


Drawbacks of Lazy Initialization:
  • No Thread-Safety that means cannot use in Multi-Threaded Environment.
  • Breakage by Serialization
  • Breakage by Cloning
  • Breakage by Java Reflection
3. Double-Checked Locking Approach:

public class MySingleton {
private static final MySingleton instance = null;
private MySingleton(){
}
public static MySingleton getInstance(){
                if( instance == null){
                       syncronized(MySingleton.class){
                                if( instance == null){
                                        instance = new MySingleton();
                                 }
                       }
                }
return instance;
}

}

Advantages of Double Checked Locking:

  • Supports Lazy-Initialization
  • Support Exception Handling
  • It creates objects on demand from Clients
  • No wastage of memory
  • Works well in Multi-Threaded Environment
Drawbacks of Double Checked Locking:
  • Breakage by Serialization
  • Breakage by Cloning
  • Breakage by Java Reflection
4. Bill Pugh Singleton Approach:

public class MySingleton {

private MySingleton(){
}

        private static class MySingletonHelper{
           private static final MySingleton instance = new MySingleton(); 
        }
public static MySingleton getInstance(){
return MySingletonHelper.instance;
}

}

Advantages of Bill Pugh Singleton:

  • Supports Lazy-Initialization
  • Support Exception Handling
  • It creates objects on demand from Clients
  • No wastage of memory
  • Works well in Multi-Threaded Environment
  • Not required external Synchronization.
Drawbacks of Double Checked Locking:
  • Breakage by Serialization
  • Breakage by Cloning
  • Breakage by Java Reflection
5. Enum Approach:

Why should we use Enum as Singleton in Java?

a) It are very easy to write Singleton Objects using Enums.
b) Enum are globally accessible
c) By Default, only one instance of Enum is created in JVM.
d) Enums are Thread-Safe by default (No need external synchronization) and guaranteed by JVM
e) Enum Singletons handle Serialization and Deserialization  by themselves and guaranteed by JVM

Example:

public enum MyEnumSingleton{
 INSTANCE;
}

Drawback of Enum Singleton:

a) It does NOT support Lazy-Initialization.


How to solve Serialization Problems with Singleton Pattern:

If we don't follow the following approach, Serialization  will breaks Singleton Pattern Implementation.

Implement readResolve() method as shown below:


public class MySingleton implements Serializable{


      private static final long serialVersionUID = 1L;

private static final MySingleton instance = null;
private MySingleton(){
}

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

        protected Object readResolve() throws ObjectStreamException
        {
                return getInstance();
        }

        protected Object writeReplace() throws ObjectStreamException
        {
                return getInstance();
        }


}


We need to implement readResolve() method because during Serialization process readObject() is used to create instance and it return new instance every time. 

However, by using readResolve() method we can replace it with original Singleton instance. 

How to solve Reflection Breakage with Singleton Pattern?

Check and Throw exception in Constructor as shown below:

public class MySingleton implements Serializable{

    private static final long serialVersionUID = 1L;

private static final MySingleton instance = null;
private MySingleton(){
   if( MySingleton.instance != null ) {
             throw new RuntimeException("Invalid" );
            }
}

        public static MySingleton getInstance(){
          if( instance == null){
                 syncronized(MySingleton.class){
                     if( instance == null){
                                 instance = new MySingleton();
                     }
                 }
          }
  return instance;
        }

        protected Object readResolve() throws ObjectStreamException
        {
                return getInstance();
        }

        protected Object writeReplace() throws ObjectStreamException
        {
                return getInstance();
        }


}

Singleton Pattern with "volatile" modifier:

The "volatile" modifier gives latest up-to-date value always in a most accurate manner in Multi-Threaded Environment.

 private static volatile final MySingleton instance = null;

How to solve clone() Breakage with Singleton Pattern?

Implement clone() as shown below.

public class MySingleton implements Serializable{

    private static volatile final long serialVersionUID = 1L;

    private static final MySingleton instance = null;
    private MySingleton(){
if( MySingleton.instance != null ) {
             throw new RuntimeException("Reflection is not allowed." );
        }
    }

   public static MySingleton getInstance(){
          if( instance == null){
                 syncronized(MySingleton.class){
                     if( instance == null){
                                 instance = new MySingleton();
                     }
                 }
          }
return instance;
   }

   @Override
    protected Object readResolve() throws ObjectStreamException
    {
return getInstance();
    }

    @Override
    protected Object writeReplace() throws ObjectStreamException
    {
return getInstance();
    }

   @Override
    protected Object clone() throws CloneNotSupportedException {
        throw new CloneNotSupportedException("Cloning is not allowed"); 
    }


}

This final version is the best Singleton Design Pattern approach.

Singleton Pattern Vs Static Class?



  • When our class does not have any state, then use Static class.
  • When our class have some state, then don't use Static class.
  • Static class provides better performance than Singleton class because it is evaluated at compile time.
  • Static class is not flexible because it does not support overriding. We cannot override static methods in Java.
  • Single class can support Inheritance and Polymorphism where Static class cannot.
  • Static classes are always eagerly loaded where as Singletons can be implemented using Lazy loading approach.
  • Testing Static class is bit tough than Singleton class. But both are bit tough to test.
  • We can clone Singleton class object where as Static class does not support this.
  • Singleton objects store in Heap Memory where as Static class objects store in Stack Memory.


No comments:

Post a Comment