Singleton Pattern

By | March 17, 2017 | 153 Views
1. Definition. 2.2 Thread-safe.
2. Implementation. 2.3 Improve performance.
2.1 Classic Singleton. 2.4. Singleton inheritance problem.

1. Definition.

Singleton Pattern makes sure that a class only have one instance and provide a global point of access to it. It also belongs to Creation Pattern Group.

Singleton Pattern should be used where we only need one of: Thread pools, caches, dialog boxes, object that handle preferences and registry settings, objects used of logging, and objects that act as device drivers to devices like printers and graphics cards.

2. Implementation.

Implementation of Singleton Pattern makes use of a private constructor, a static method combined with a static variable.

2.1 Classic Singleton.


This is also called a lazy create instance.

// NOTE: This is not thread safe!

public class Singleton {
	private static Singleton uniqueInstance;
 
	// other useful instance variables here
 
	private Singleton() {}
 
	public static Singleton getInstance() {
		if (uniqueInstance == null) {
			uniqueInstance = new Singleton();
		}
		return uniqueInstance;
	}
 
	// other useful methods here
}

2.2 Thread-safe.

Supposed that we have two threads, each executing the code above. So JMV, actually runs two threads and get a hold of different Singleton Objects. By adding the synchronized keyword to getInstance(), we force every thread to wait it turn before it can enter the method. This makes it possible for no two threads entering the method at the same time.

public class Singleton {
	private static Singleton uniqueInstance;
 
	// other useful instance variables here
 
	private Singleton() {}
 
	public static synchronized Singleton getInstance() {
		if (uniqueInstance == null) {
			uniqueInstance = new Singleton();
		}
		return uniqueInstance;
	}
 
	// other useful methods here
}

2.3 Improve performance.

The problem here when we use synchronization is very expensive. This is because only the first time goes through this method to set uniqueInstance variable to an instance of Singleton, then we have no further need to synchronize this method. Therefore, multi-threads will spend much time to check and wait their turns. Some solutions presented below:

An eagerly created instance rather than a lazily created one

public class Singleton {
	private static Singleton uniqueInstance = new Singleton();
 
	private Singleton() {}
 
	public static Singleton getInstance() {
        // We’ve already got an instance, so just return it.
		return uniqueInstance;
	}
}

With such the solution, the JVM to create the unique instance of the Singleton when the class is loaded. The JVM guarantees that the instance will be created before any thread accesses the static uniqueInstance variable.

Lazy instantiation using double-checked locking mechanism.
This solution reduces the use of synchonization in getInstance(). We use volatile and double-check null of uniqueInstance variable.

// This implementation of Singleton supports for Java 5+

public class Singleton {
    // Volatile ensures that multiple threads 
    // handle the uniqueInstance variable correctly when it
    // is being initialized to the Singleton instance.
	private volatile static Singleton uniqueInstance;
 
	private Singleton() {}
 
	public static Singleton getInstance() {
        // Only the fist time, check for an instance and 
        // if there isn't one, enter synchronized block.
		if (uniqueInstance == null) {
			synchronized (Singleton.class) {
                // Check it again and if still null,
                // create a new instance.
				if (uniqueInstance == null) {
					uniqueInstance = new Singleton();
				}
			}
		}
		return uniqueInstance;
	}
}

2.4. Singleton inheritance problem.


The Singleton code runs into a problem.

// Define a Singleton class.
public class Singleton {
	protected static Singleton uniqueInstance;
 
	protected Singleton() {}
 
	public static synchronized Singleton getInstance() {
		if (uniqueInstance == null) {
			uniqueInstance = new Singleton();
		}
		return uniqueInstance;
	}

}
// Define a Log4jSingleton subclass.
public class Log4jSingleton extends Singleton {

	private Log4jSingleton() {
		super();
	}
 
}
// Define a LoggerSingleton subclass.
public class LoggerSingleton extends Singleton {
	
	private LoggerSingleton() {
		super();
	}
 
}

Now we test it with SingletonTestDrive class as following:

public class SingletonTestDrive {
	public static void main(String[] args) {
		Singleton jdkLogger = LoggerSingleton.getInstance();
		Singleton log4j = Log4jSingleton.getInstance();
		System.out.println(jdkLogger);
		System.out.println(log4j);
 	}
}

Surprisingly, the output showed just one instance created. Because the constructor is private so that we can’t extend a class with a private constructor.

Singleton@1db9742
Singleton@1db9742

References:

Leave a Reply

Your email address will not be published. Required fields are marked *