Saturday, 15 August 2015

Singleton pattern in java and singleton implentation

Singleton Pattern: 
Singleton pattern in java means there should only be a single instance(object) of the class across the application.

Implementation :
Singleton can be implemented in various ways, following program depicts Singleton implementation.
Comments are given for each type of singleton implementation.

There are certain issues which can break Singleton pact:
  •  Using Reflection one can call the constructor and initialize an Object. - To prevent throw an exception inside constructor.
  • Using Serialization - To prevent return same instance in readResolve().
  • Using clone - To prevent throw error in clone().

import java.lang.reflect.Constructor;

/**
 * @author vikky.agrawal
 * @see http://stackoverflow.com/questions/20421920/what-are-the-different-ways-we
 *      -can-break-a-singleton-pattern-in-java
 */

public class Singleton {
// here volatile works with java 1.5 and above.
    private volatile static Singleton single_instance;

    private Singleton() {
        // preventing reflection
        if (single_instance != null) {
            throw new IllegalStateException(
                    "Singleton instance already created.");
        }
        System.out.println("Singleton constructor running");

    }

    public static Singleton getSingleton() {

        // double lock mechanism
        if (single_instance == null) {
            // if 1st thread is executing here then second thread might have checked 
            // above condition hence both threads may exist here.
            synchronized (Singleton.class) {
                // prevent multiple threads from creating 2 instances.(2 phase
                // lock)
                if (single_instance == null)
                    single_instance = new Singleton();
            }
        }
        return single_instance;
    }

    // preventing de-serialization
    protected Object readResolve() {
        return getSingleton();
    }

    // preventing cloning
    @Override
    public Object clone() throws CloneNotSupportedException {
        // return INSTANCE
        throw new CloneNotSupportedException();
    }

    public static void main(String args[]) throws Exception {
        // Breaking the singleton pact

        Singleton s = Singleton.getSingleton();

        Class<Singleton> clazz = Singleton.class;

        Constructor<Singleton> cons = clazz.getDeclaredConstructor();
        cons.setAccessible(true);

        Singleton s2 = (Singleton) cons.newInstance();
        System.out.println(s.hashCode());
        System.out.println(s2.hashCode());
    }

}

// using static class pattern

class BillPughSingleton {

    @SuppressWarnings("unused")
    private static final long serialVersionUID = 1L;

    private BillPughSingleton() {
    }

    private static class LazyHolder {
        private static final BillPughSingleton INSTANCE = new BillPughSingleton();

    }

    public static BillPughSingleton getInstance() {
        return LazyHolder.INSTANCE;
    }

    protected Object readResolve() {
        return getInstance();
    }
}
// Using early instantiation -- static

class SingletonStatic {
    private static SingletonStatic instance = new SingletonStatic();

    private SingletonStatic() {
        System.out.println("Singleton(): Initializing Instance");
    }

    public static SingletonStatic getInstance() {
        return instance;
    }
}

// Using Enum

enum SingletonEnum {

    INSTANCE;

    public void distributePresents() {
        // elided
    }

    /** Demonstrate use of SantaClaus. */
    public static void main(String... aArgs) {
        SingletonEnum fatGuy = SingletonEnum.INSTANCE;
        fatGuy.distributePresents();

    }
}