Creational Pattern: Singleton
This article discusses how the Singleton pattern enforces only a single instance of a class ever to get produced and exist through the lifetime of an application.
What is it?
A singleton is a design pattern used to create the only class instance. Singleton pattern is typically used when there are several examples where only a single instance of a class should exist and the constraint be enforced. For example, caches, thread pools, and registries should only have one instance.
Make the constructor private to ensure that only one class object is created. That way, only the class members can access the private constructor and no one else.
In the real world, the Singleton pattern ensures that only a single class instance exists and offers a global point of access to it.
Class Diagram
The class diagram contains only one entity.
Singleton
Example
Let’s say we want to model the American President’s official aircraft called Airforce One in our software. Singleton class is the best-suited representation for an entity with only one instance.
Here is the code for our singleton class:
Multithreading and Singleton
This code works as long as the application is single-threaded. However, if multiple threads access this class, there is a possibility that various objects will be created.
For example:
- Thread A calls the method
getInstance
and finds theonlyInstance
to be null; however, before it can create an instance, it is context switched out. - Now thread B comes along and calls
getInstance
, which returns theAirforceOne
object. - If thread A is scheduled again, the mischief begins. The thread is already past the if-null condition check and will proceed to create a new
AirforceOne
object and assign it toonlyInstance
. Now there are two differentAirforceOne
objects out in the wild, one with thread A and one with thread B.
There are two simple ways to fix this race condition.
- By adding
synchronized
to thegetInstance()
method, you can achieve thread safety.
- Another option is to initialize the instance statically, guaranteeing it is thread-safe.
The problem with the above approaches is that synchronization is expensive and static initialization creates the object even if it’s not used in a particular application run. So if the object creation is expensive, then static initialization can cost us performance.
Double-Checked Locking
There are two significant problems with the approaches described above: synchronization is expensive and static initialization creates the object even if it’s not used in a particular application run. If the object creation is expensive, then static initialization can cost us performance.
The above solution marks the singleton instance volatile. However, this implementation of the JVM’s volatile
methodology will not work correctly for double-checked locking, and you’ll need another approach to create your singletons.
The double-checked locking idiom is now considered an antipattern, and its utility has primarily passed away as JVM startup times have sped up.
Other Examples
The Java API provides us with the following singletons:
java.lang.Runtime
java.awt.Desktop
Caveats
You can subclass a singleton class by protecting the constructor instead of private. However, there are better choices than this under all circumstances. In these situations, developers can create a registry of singletons for all the subclasses. The getInstance method can take in a parameter or use an environment variable to return the desired singleton object. The registry maintains a mapping of string names to singleton objects.
Other articles in the Creational Pattern series
- Creational Pattern: Builder
- Creational Pattern: Prototype
- Creational Pattern: Factory Method
- Creational Pattern: Abstract Factory
My other publications: https://ercindedeoglu.github.io/