Purpose of the pattern
Ensure that a class has a single instance and provide a single access point to that instance.
Why use the Singleton pattern
We need to ensure that a class has only one instance. For example, we might have multiple printers but we only want to take advantage of one print queue. Or within an operating system, we would like to be able to use only one Window Manager. A use case in the Web programming, could be the creation of a DAO (Data Access Object) class; it is a good idea to create a single instance for such a class.
Structure
As you might guess, this pattern belongs to the category of creation patterns. Let's write a Singleton class in Java:
public class Singleton {
private static Singleton instance;
private Singleton() {}
public static Singleton getInstance() {
if(instance == null) {
instance = new Singleton();
}
return instance;
}
public void singletonOperation() {
System.out.println("I am a Singleton class");
}
}
Note two aspects that characterize this pattern:
The constructor is private: we do not allow the client to create a Singleton class with new. The Singleton class is responsible for creating its own unique instance.
The getInstance method is a class method (in Java the keyword static is used) that ensures the creation of the only instance that will be available to clients, initializing the instance variable the first time the method is called: this approach is called lazy initialization.
The clients, in order to use the Singleton class, must call the getInstance method, that it supplies therefore a single point of access to the instance.
Management of a Singleton Thread Safe
With the previous implementation, creating the Singleton in getInstance, is not thread safe. To make it so, we must ensure that in a multithreaded environment, the creation of the instance is done only once (we lock the check if the instance variable is null, using the keyword synchronized in Java). One of the ways to do this is as follows:
private static volatile Singleton instance;
...
public static Singleton getInstance() {
if(instance == null) {
synchronized (Singleton.class) {
if(instance == null) {
instance = new Singleton();
}
}
}
return instance;
}
Note that the check is performed twice.
This is to avoid the risk that a pending thread from the synchronized block could overwrite instance
already initialized by a previous thread.
Moreover, in Java we can exploit the functionality of the keyword volatile, that allows the access in reading of a
variable by a thread only after the end of the writing phase.
A simpler alternative is to make the entire getInstance method thread safe (keyword synchronized at the level of the method), but this makes the singleton reading phase very inefficient.
Another alternative is to initialize instance at startup:
public class Singleton {
private static final Singleton INSTANCE = new Singleton();
...
public static Singleton getInstance() {
return INSTANCE;
}
...
}
In this way, however, we do not use lazy initialization, we instantiate the Singleton even if it will never be used.
There are other alternatives, such as declaring the Singleton as an Enum, or delegating the initialization of the Singleton to an inner class of it.
Create subclasses of a Singleton
By having the constructor private, we not only don't give clients the ability to instantiate the Singleton, but also not being able to define subclasses: this is the normal behavior of a Singleton.
However, it is possible to use workarounds to achieve this.
We can, for example, create a registry of Singleton, and the client, through a variable of environment, decides which implementation to use. The Singleton class does not have to be responsible for knowing its subclasses, it just needs to retrieve from the registry the subclass that the user wants to use, based on the environment variable. Let's see how to do this:
public abstract class Singleton {
private static Singleton instance;
protected static Map<String, Singleton> registry = new HashMap<>();
protected Singleton() {}
public static Singleton getInstance() {
if(instance == null) {
String singletonName = System.getenv("singleton");
instance = registry.get(singletonName);
if(instance == null) {
throw new RuntimeException("No Singleton implementation found!");
}
}
return instance;
}
public abstract void singletonOperation();
}
We note that the Singleton has a registry variable that is a key-value map, with the key representing the name of a singleton implementation and the value representing its corresponding instance.
We also note that the constructor, obviously, is no longer private, but protected (in Java keyword protected), so as to be callable at least within the possible subclasses.
An example implementation might be:
class SubSingletonA extends Singleton {
static {
registry.put("A", new SubSingletonA());
}
private SubSingletonA() { }
@Override
public void singletonOperation() {
System.out.println("I am the SubSingletonA class");
}
}
The subclass will have the only responsibility of adding its own instance to the registry.
Conclusions
We have seen what is the Singleton pattern, one of the most used creation patterns.
We have also seen that this pattern, in its natural form, gives constraints to the programmer. In the testing phase for example,
it is not possible to mock this class type.
If possible, it is preferable to use beans (e.g. via Spring) with a singleton scope rather than using a Singleton class, because beans are more powerful; they ensure that there is only one instance but allow for easy testing as they can be mocked easily.