This post will look at many ways to implement the Singleton pattern in Java. We will focus on the intent of the Singleton pattern, implementing it, and benefits of choosing one implementation over the other.
What is a Singleton pattern in Java?
This pattern ensures that there is only one instance of a class inside your application. When developing your application, it can be essential that only one instance of a class is available at a time. A use-case of the singleton pattern could be: many clients need access to the same logging instance when you create a logging framework. Another use-case could be an instance of a file-system instance that you want to share with multiple clients.
The Singleton pattern works by giving the class the responsibility to create and manage its instance. We achieve this by making the constructor private so other classes can't call the constructor to create an instance, instead, we provide one (or more) methods for clients to retrieve a reference to the singleton instance
Why Singleton pattern is used in Java?
The Singleton pattern gives controlled access to a class, its only instance, and its creation. This encapsulation allows us to control how and if a client could obtain a reference to the instance. The Singleton pattern could also be altered to support multiple instances instead of a single one. To do this, you would only have to change or add a method the clients use to obtain a reference to the instance.
Using Class for Singleton pattern
We will start by implementing the Singleton pattern using a Java class. In the example below, we have the class
SingletonClass and made its
constructor private and implemented a static method for clients to obtain a reference to the instance.
Here is an example of how we could obtain and use a reference to the singleton class instance. In the example, we obtain
two references and use one to set the amount and the other reference to get the amount. The output to the console for this code is
anotherReference amount = 1.
Eager initialization of the Singleton
When we eagerly initialize a singleton class, we make sure that the instance of the class is created before a client calls the method to obtain a reference to the instance.
Lazy initialization of the Singleton
Creating the singleton instance when a client asks for a reference is called lazy initialization. Implementing the pattern this way requires you to add some logic to check if the instance is already created. The first call made to get an instance wilL also take a longer time to complete because the instance has to be initialized for the first time.
Can we serialize singleton class in Java?
You can use serialization to create multiple instances of a Singleton. To prevent others from creating numerous instances,
your class must implement the
Serializable interface and the
readResolve() method. The
readResolve method should return the
singleton instance that has already been created and is referenced by other clients. Make sure also to make the fields transient,
so they can't be misused during serialization.
Support a variable amount of Singleton instances
We can implement the Singleton in a way that supports a variable amount of singletons. We can do this because the
responsibility for creating instances is encapsulated inside the class. The example below uses a
map to keep track of
all the created instances. In the example below, an instance of
VariableAmountOfSingletonClass is associated with only one name;
there can't be two instances with the same name.
Here is an example of how we would use this class:
The console output for this code is;
Using Enum for Singleton pattern
Using an Enum is considered the best way to implement the Singleton pattern in Java. It ensures that there will be only
one instance of the singleton inside our application. When you use
Enum you don't have to
worry about reflection, and you don't need to implement the Serializable interface yourself.
How you could use this Singleton:
We implemented the Singleton pattern in Java in this post using a class and enum; and the benefits of using an Enum to implement this pattern. We also saw the difference between lazy and eager initialization of the singleton instance. Using a Map, we also implemented a variation of the Singleton pattern that supports multiple instances because the initialization is encapsulated inside its class.