The Singleton Pattern ensures a class has only one instance, and provides a global point of access to it.
The Singleton pattern ensures you have at most one instance of a class in your application.
It provides a global access point to that instance by managing itself.
It is implemented with a private constructor, a static method to create a new instance of your Singleton class
in case none exists, or return the instance that already exists using a static member variable of the Singleton class type.
The singleton pattern is taking on two responsibilities: It is not only responsible for managing its one instance (and providing global access), it is also responsible for whatever its main role is intended. A singleton should not be inherited from because its constructor should remain private.
When designing multithreaded applications we need to examine the performance and resource constraints while carefully choosing an appropriate Singleton implementation. Beware of the double-checked locking implementation which can be not thread-safe.
The singleton is similar to global variables but without the downside of getting created at program start like global variables. Instead, the singleton can be created only when it is needed, which can avoid time consuming instantiation. This is called lazy instantiation.
Examples where singletons are useful are:
- thread pools
- caches
- dialog boxes
- objects that handle preferences and registry settings
- objects used for logging
- objects that act as device drivers to devices like printers and graphics cards.
In fact, for many of these types of objects, if we were to instantiate more than one we’d run into all sorts of problems like incorrect program behavior, overuse of resources, or inconsistent results. By making use of the Singleton one can assure that every object in an application is making use of the same global resource.
The simplest form of the Singleton Pattern is the following.
Note that this simple implementation is not thread safe.
The class contains a static variable uniqueInstance
of its own class type Singleton
to hold one instance.
The constructor is decleared private, which allows only Singleton
to instantiate this class.
The static getInstance()
method enables us to instantiate the class and also to return an instance of it.
Of course the Singleton
class can have other useful member variables and methods.
The static method getInstance()
works as follows:
If uniqueInstance
is null
, then no instance was created yet. In this case, Singleton
is instantiated through
its private constructor and assigned to to uniqueInstance
. If uniqueInstance
wasn’t null
,
then it was previously created and is therefore returned. Because the getInstance()
is a static method,
it allows access from anywhere in the code using Singleton::getInstance()
.
This is just as easy as accessing a global variable but with the advantage of lazy instantiaion.
Note that if we never need the instance, it never gets created. This is lazy instantiation.
To deal with multithreading one way is to make getInstance()
synchronized (Java keyword),
which forces every thread to wait its turn before it can enter the method.
This way, no two threads may enter the method at the same time.
Note that this method, using synchronize, is expensive and the synchronization is only relevant the first time when there was no instance created yet. Once we've set the `uniqueInstance` variable to an intace of `Singleton`, we have no further need to synchronize this method.
If the performance of getInstance()
is not critical to your application and therefore not causing any substantial overhead then synchronize
is ok to use.
If your application always creates and uses an instance of Singleton
or the overhead of creation and runtime aspects of the Singleton
are not onerous, you may want to create your Singleton
eagerly, like this:
Here an instance of Singleton
is created static, which makes this code guaranteed to be thread safe.
Another method is to use double-checked locking to reduce the use of synchronization in getInstance()
.
With double-checked locking, we first check to see if an instance is created, and if not, THEN we synchronize. This way, we only synchronize the first time through, just what we want.
A main program that uses the Singleton
class can look like this:
The output of the thread safe implementation would be:
Comments