Singleton pattern
- Definition
- Purpose
- When to use the Singleton Design Pattern?
- Overview
- Why to use the Singleton Design Pattern?
- Real world examples
- Steps to build a Singleton class
- 1. make the constructor private
- 2. Declare a static volatile class variable for the instance of this class
- 3. provide the instance of this class to other places in the application using a public static volatile method
- 4. Consider lazy-initialization or eager-initialization
- 5. Handle multi-threading by using synchronized keyword
- 6. Consider the implications of synchronizing
- Difference between having a singleton and not having a singleton
- Can we just create a class in which all methods and variables are defined as static? Wouldn’t that be the same as a Singleton?
- Gotchas
- Conclusion
- Internal Implementation
- Reading material
- Questions
- Tags
Definition
The Singleton pattern ensures a class has only one instance in the JVM, and provides a global point of access to it.
Purpose
Singleton controls concurrent access to resources.
When to use the Singleton Design Pattern?
- We should use the Singleton Design Pattern when we want to share a single object among multiple users/callers. For example, a database connection.
- We should use the Singleton Design Pattern when we want stricter control over global variables. Remember, no one except the Singleton class itself can replace the cached instance.
Overview
Using Singleton pattern, we create one-of-a-kind objects for which there is only one instance. This is the simplest in terms of it’s class diagram; in fact, the diagram holds just one class. Despite its simplicity from a design class design perspective, there are quite a few bumps and potholes in its implementation.
Why to use the Singleton Design Pattern?
There are many objects we only need one of; connection or thread pools, caches, dialog boxes, objects that handle preferences and registry settings, objects used for logging, and objects that act as device drivers to devices like printers and graphic cards. For many of these type of objects, if we were to instantiate more than one, we would run into all sorts of problems like incorrect program behavior, overuse of resources, or inconsistent results. Using Singleton classes, we can assure that every object in your application is making use of the same global resource.
Why do we need this pattern? If there are classes that should only be instantiated once, can’t we just do this by convention or by global variables? In java, we can do it with static variable. The Singleton pattern is a time-tested method for ensuring only one object (one instance of the class) gets created. The pattern also gives us a global point of access, just like a global variable, but without the downsides. What is an example of a downside? If you assign an object to a global variable, then that object might be created when your application begins. What if this object is resouce intensive and your application never ends up using it? With Singleton pattern, we can create our objects only when they are needed.
There are situations in which a singleton class is useful. Typical examples are classes that we could shortly describe as “managers”. These are classes which manage resources, read data from configuration files, instantiate threads etc. If you were making a role-playing game, you would probably have multiple “Item” objects or multiple “Level” objects, but it would make sense to make the “Score” class singleton – since you only need one object to take care of the player’s score.
Another example could be a factory with multiple manufacturing tracks. The tracks are the ones that actually do all the work, whether it is packing cans or making car parts. However, it is the “factory manager” that decides how many tracks will be working, for how long, and what they are going to do.
Real world examples
Here is the list of some of the known real world example using the singleton pattern:
- Logger : In enterprise applications, the Logger object is a real-world example of a Singleton pattern. If this class is not a singleton, there will be a new log file created for every user call (client applications). All the logs will be written in a single file using this design.
- Cache : To have a global point of reference, it can also create the cache classes as Singleton objects. Once again, in real-life client applications will interact with the same cache objects for cache entries.
- Configuration File : In enterprise applications, the configuration/properties can be based on the Singleton pattern. With this, multiple client applications will use the same files (that’s the idea anyway, that configuration mostly remains the same for all the clients).
- JDK / Spring uses Singleton Pattern
- java.lang.Runtime#getRuntime()
- java.awt.Desktop#getDesktop()
- java.lang.System#getSecurityManager()
- Spring Bean Scope
Steps to build a Singleton class
- In multithreaded applications, lazy instantiation can cause race conditions. Therefore, use double-checked locking to prevent the creation of multiple instances by different threads
public MyClass {
}
How would we create a new object of this class? new MyClass()
1. make the constructor private
Now, lets make it’s constructor private.
public MyClass {
private MyClass() {}
}
The constructor is declared private.
Now, MyClass cannot be instantiated from anywhere outside of the code in MyClass itself.
Only Singleton (the current class) can instantiate this class.
2. Declare a static volatile class variable for the instance of this class
private static volatile MyClass uniqueInstance = null;
uniqueInstance
is the static variable to hold the one instance of the class Singleton.
The volatile
keyword ensures that multiple threads handle the uniqueInstance variable correctly when it is being instantiated to the Singleton instance.
3. provide the instance of this class to other places in the application using a public static volatile method
If no other object can instantiate an object of MyClass, how is it going to be useful? We need a way to provide the instance of this class to other places in the application. How do we do that? By putting a static method in it. The static method can be called like this: MyClass.getInstance()
public MyClass {
private static volatile MyClass uniqueInstance = null;
private MyClass() {}
public static MyClass getInstance() {}
}
getInstance()
gives a way to instantiate the class and also to return an instance of it. To get a hold of an Singleton object, we don’t instantiate one, we just ask for an instance.
4. Consider lazy-initialization or eager-initialization
Eager-initialization
If the overhead of creation and runtime aspects of the Singleton are not that bad, you can do this: Move to an eagerly created instance rather than a lazily created one.
public class Singleton {
private static final Singleton INSTANCE = new Singleton();
private Singleton() {}
public static Singleton getInstance() {
return INSTANCE;
}
}
Using this approach, we rely on the JVM to create the unique instance of the Singleton when the class is loaded. The JVM will guarantee that the instance will be created before any thread accesses the static uniqueInstance variable.
Lazy-initialization
If performance implications of creating the Singleton at application start-up or for some other reasons, the Singleton cannot be created until it is requested the first time, use lazy-initialization to not create the intance until the static getter is called the first time.
The instance is lazily created (it is created when someone asks for it) instead of getting eagerly created.
public class MyClass {
private static volatile MyClass uniqueInstance = null;
// other useful instance variables here
public static MyClass getInstance() {
uniqueInstance = new MyClass();
return uniqueInstance;
}
// other useful methods here
}
5. Handle multi-threading by using synchronized keyword
The multithreading woes can be fixed my making getInstance() a synchronized method:
public static synchronized MyClass getInstance() {
if (uniqueInstance == null) {
uniqueInstance = new MyClass();
}
return uniqueInstance;
}
By adding the synchronized
keyword to getInstance(), we force every thread to wait its turn before it can enter the method. That is, no two threads may enter the method at the same time.
6. Consider the implications of synchronizing
It is expensive to synchronize the getInstance() method. Synchronizing a method can decrease performance by a factor of 100.
So, what do we do? Here are a few options.
Don’t use synchronization
Do nothing if the performance of getInstance() is not critical to the application.
If calling the getInstance() method is not causing substantial overhead for your application, don’t do anything. Synchronizing getInstance() is straightforward and effective. If a high-traffic part of your code begins using getInstance(), you may have to reconsider.
Use double-checked locking before synchronizing
If synchorization absolutely needs to be used, consider double-checked locking to reduce the use of synchronization
Use double-checked locking to reduce the use of synchronization in getInstance()
With this approach, we first check to see if an instance is created, and if not, then we synchronize. This way, we only synchronize the first time. In the synchronized block, check again and if still not null, create an instance.
public class Singleton {
private volatile static Singleton uniqueInstance;
private Singleton() {}
public static Singleton getInstance() {
if (uniqueInstance == null) {
synchronized (Singleton.class) {
if (uniqueInstance == null) {
uniqueInstance = new Singleton();
}
}
}
return uniqueInstance;
}
}
If performance is an issue in your use of the getInstance() method, then this method of implementing the Singleton can drastically reduce the overhead.
Difference between having a singleton and not having a singleton
We have a class that is not Singleton.
public class ChocolateBoiler {
private boolean empty;
private boolean boiled;
public ChocolateBoiler() {
empty = true;
boiled = false;
}
public void fill() {
if (isEmpty()) {
empty = false;
boiled = false;
// fill the boiler with a milk/chocolate mixture
}
}
public void drain() {
if (!isEmpty() && isBoiled()) {
// drain the boiled milk and chocolate
empty = true;
}
}
public void boil() {
if (!isEmpty() && !isBoiled()) {
// bring the contents to a boil
boiled = true;
}
}
public boolean isEmpty() {
return empty;
}
public boolean isBoiled() {
return boiled;
}
}
If two ChocolateBoiler instances get loose, some very bad things can happen due to the functionality in the fill(), drain() and boil() methods.
Lets turn this into a Singleton.
public class ChocolateBoiler {
private boolean empty;
private boolean boiled;
private staic ChocolateBoiler uniqueInstance;
private ChocolateBoiler() {
empty = true;
boiled = false;
}
public static ChocolateBoiler getInstance() {
if (uniqueInstance == null) {
uniqueInstance = new ChocolateBoiler();
}
return uniqueInstance;
}
public void fill() {
if (isEmpty()) {
empty = false;
boiled = false;
// fill the boiler with a milk/chocolate mixture
}
}
public void drain() {
if (!isEmpty() && isBoiled()) {
// drain the boiled milk and chocolate
empty = true;
}
}
public void boil() {
if (!isEmpty() && !isBoiled()) {
// bring the contents to a boil
boiled = true;
}
}
public boolean isEmpty() {
return empty;
}
public boolean isBoiled() {
return boiled;
}
}
Despite the fact we improved the code using Classic Singleton, there is a possibility that two instances of ChocolateBoiler can get instantiate. How? Two separate threads can call ChocolateBoiler.getInstance() at the same time. And that can result in two different objects being returned. There can be two ChocolateBoiler instances.
How to fix this?
Can we just create a class in which all methods and variables are defined as static? Wouldn’t that be the same as a Singleton?
Yes, if your class is self-contained and doesn’t depend on complex initialization. However, because of the way static initializations are handled in Java, this can get very messy especially if multiple classes are involved. Often, this scenario can result in subtle, hard-to-find bugs involving order of initialization. Unless there is a compelling need to implement your “singleton” this way, it is far better to stay in the object world.
Gotchas
If you are using multiple classloaders and Singletons, be careful. If you have two or more class loaders, you can load the same class multiple times. If that class happens to be a Singleton, then since we have more than one version of the class, we also have more than one instance of the Singleton. One way around this problem is to specify the classloader yourself.
Conclusion
These are very valid arguments. However, Singletons are useful in situations like the ones we’ve discussed in the previous paragraphs, when one class needs to manage resources for other classes and when having more instances than one would truly be a design flaw. With prudent, moderate usage and implementations which can be optimized for thread-safety, serialization or faster performance, the singleton pattern can improve the overall readability and elegance of your code. This design pattern should not be avoided since the Singleton Design Pattern is, after all, a classic Gang of Four design pattern.
Internal Implementation
Reading material
https://www.javadevjournal.com/java-design-patterns/singleton-design-pattern/
Questions
What feature of java helps implement this pattern?