In this Java tutorial, you will learn what a Singleton class is, when to use it, how early loading and lazy loading differ, how to make lazy loading thread-safe, and how enum-based Singleton works in Java with examples.
Singleton Class in Java
A Singleton class in Java is a class that allows only one object of that class to be created and provides a controlled way to access that object.
In practice, Singleton is a creational design pattern. It is used when exactly one shared instance should coordinate a resource or service across an application. A typical Singleton class has a private constructor, a private static reference to its own instance, and a public static access method or enum constant that returns the same instance whenever it is requested.
The important point is that Singleton controls object creation. Other classes should not be able to call new directly on the Singleton class.
When is Singleton Class used in Java?
Singleton class is used when a single shared object has to be maintained throughout the application life cycle. For example, the same logger, configuration manager, application cache, or connection factory may need to be accessed from many classes, but the object itself should be created only once.
Use Singleton only when the single-instance requirement is real. If the class simply contains utility methods and no state, a utility class with static methods may be clearer. If the object has dependencies or needs to be replaced in tests, dependency injection is often better than using a global Singleton directly.
What is the Structure of Singleton Class?
A Java Singleton usually contains three parts:
- A private constructor, so that other classes cannot instantiate it directly.
- A static field that stores the only instance of the class.
- A public static method, commonly named
getInstance(), that returns the same instance every time.
Following is a picture that depicts the structure of Singleton Class :

How to implement Singleton Class in Java
Singleton class in Java can be implemented in different ways depending on when the object should be created and whether the code runs in a multi-threaded environment.
Singleton class in Java using early loading
In early loading, the Singleton instance is created when the class is loaded. This approach is simple and thread-safe because class initialization in Java is handled by the JVM. It is a good choice when the object is lightweight or definitely required during application execution.
The instance could be initialized directly during the instance declaration. JVM Java Virtual Machine takes care of creation of instance of the Singleton class. An example is shown below.
SingletonCls.java
/**
* Singleton Class in Java with Early loading
*/
public class SingletonCls {
// singleton instance, this instance is created in JVM during start of the application
// which is early loading
private static final SingletonCls singletonInst = new SingletonCls();
// a variable of singleton class
private String message = "";
// making constructor private so that no other class could use the default constructor
private SingletonCls() {
}
// the method which gives access to the only instance of SingletonCls
public static SingletonCls getInstance(){
return singletonInst;
}
// getter for the vairable message
public String getMessage() {
return message;
}
// setter for the variable message
public void setMessage(String message) {
this.message = message;
}
}
Accessing the above Singleton class in another class is shown using ExamplePgm.java as following.
ExamplePgm.java
/**
* Example class that demonstrates the usage of Singleton class
*/
public class ExamplePgm {
public static void main(String[] args) {
// access instance of SingletonCls using getInstance() method
SingletonCls instance = SingletonCls.getInstance();
instance.setMessage("This message is set in main of ExamplePgm");
displayMsg();
}
public static void displayMsg(){
SingletonCls instance = SingletonCls.getInstance();
System.out.println(instance.getMessage());
}
}
Output to the console when the above program is run is shown below :
Starting of ExamplePgm..
This message is set in main of ExamplePgm
The same object is returned in main() and displayMsg(). Therefore, the message set through one reference is available through the other reference also.
Singleton class in Java using lazy loading
In lazy loading, the Singleton object is not created when the class is loaded. It is created only when getInstance() is called for the first time. This is useful when the object is expensive to create and may not always be needed.
The instance could be initialized only when the Singleton Class is used for the first time. Doing so creates the instance of the Singleton class in the JVM Java Virtual Machine during the execution of the method, which gives access to the instance, for the first time. An example is given below.
SingletonCls.java
/**
* Singleton Class in Java with Lazy loading
*/
public class SingletonCls {
// singleton instance declaration
private static SingletonCls singletonInst;
// a variable of singleton class
private String message = "";
// making constructor private so that no other class could use the default constructor
private SingletonCls() {
System.out.println("Singleton instance created.");
}
// the method which gives access to the only instance of SingletonCls
public static SingletonCls getInstance(){
if(singletonInst==null){
singletonInst = new SingletonCls();
System.out.println("SingletonCls instance created for the first time.");
}
return singletonInst;
}
// getter for the variable message
public String getMessage() {
return message;
}
// setter for the variable message
public void setMessage(String message) {
this.message = message;
}
}
Accessing the above Singleton class in another class is shown using ExamplePgm.java as following.
ExamplePgm.java
/**
* Example class that uses Singleton class and its variables
*/
public class ExamplePgm {
public static void main(String[] args) {
System.out.println("Starting of ExamplePgm..");
// access instance of SingletonCls using getInstance() method
SingletonCls instance = SingletonCls.getInstance();
instance.setMessage("This message is set in main of ExamplePgm");
displayMsg();
}
public static void displayMsg(){
// SingletonCls.getInstance() gets the instance that is already created during the call in main() method, for the first time.
SingletonCls instance = SingletonCls.getInstance();
System.out.println(instance.getMessage());
}
}
Output to the console when the above program is run is shown below :
Starting of ExamplePgm..
Singleton instance created.
SingletonCls instance created for the first time.
This message is set in main of ExamplePgm
This lazy loading version is simple, but it is suitable only for single-threaded use. In a multi-threaded program, two threads may see singletonInst == null at the same time and both may create an object.
Singleton class in Java using lazy loading that is thread safe
The instance could be initialized only when the Singleton Class is used for the first time. Doing so creates the instance of the Singleton class in the JVM Java Virtual Machine during the execution of the method, which gives access to the instance, for the first time. In multi-threaded environment, it is a possible situation that two threads might enter the getInstance() method at a same time, which could create two instances of Singleton class which is not desirable and might make the program behavior unpredictable. To make the creation of Singleton instance thread safe, the method getInstance() is synchronized so that the method is executed by only one thread at a time. An example is shown below.
SingletonCls.java
/**
* Singleton Class in Java with Lazy loading
*/
public class SingletonCls {
// singleton instance declaration
private static SingletonCls singletonInst;
// a variable of singleton class
private String message = "";
// making constructor private so that no other class could use the default constructor
private SingletonCls() {
System.out.println("Singleton instance created.");
}
// the method which gives access to the only instance of SingletonCls, is thread safe
public static synchronized SingletonCls getInstance(){
if(singletonInst==null){
singletonInst = new SingletonCls();
System.out.println("SingletonCls instance created for the first time.");
}
return singletonInst;
}
// getter for the variable message
public String getMessage() {
return message;
}
// setter for the variable message
public void setMessage(String message) {
this.message = message;
}
}
Accessing the above Singleton class in another class is shown using ExamplePgm.java as following.
ExamplePgm.java
/**
* Example class that uses Singleton class and its variables
*/
public class ExamplePgm {
public static void main(String[] args) {
System.out.println("Starting of ExamplePgm..");
// access instance of SingletonCls using getInstance() method
SingletonCls instance = SingletonCls.getInstance();
instance.setMessage("This message is set in main of ExamplePgm");
displayMsg();
}
public static void displayMsg(){
// SingletonCls.getInstance() gets the instance that is already created during the call in main() method, for the first time.
SingletonCls instance = SingletonCls.getInstance();
System.out.println(instance.getMessage());
}
}
Output to the console when the above program is run is shown below :
Starting of ExamplePgm..
Singleton instance created.
SingletonCls instance created for the first time.
This message is set in main of ExamplePgm
The synchronized method solves the object-creation race condition. The trade-off is that every call to getInstance() must acquire the class-level lock, even after the Singleton object has already been created.
Thread-safe Singleton in Java using double-checked locking
Another common lazy-loading approach is double-checked locking. It synchronizes only during the first object creation. After the instance is created, later calls return the object without entering the synchronized block. In Java, the instance field should be declared volatile for this pattern.
SingletonCls.java
public class SingletonCls {
private static volatile SingletonCls singletonInst;
private SingletonCls() {
}
public static SingletonCls getInstance() {
if (singletonInst == null) {
synchronized (SingletonCls.class) {
if (singletonInst == null) {
singletonInst = new SingletonCls();
}
}
}
return singletonInst;
}
}
The first if avoids synchronization after initialization. The second if, inside the synchronized block, prevents another thread from creating a second object while the first thread is already creating it.
Singleton class in Java using initialization-on-demand holder idiom
The initialization-on-demand holder idiom is a clean way to get lazy loading and thread safety without synchronizing every access. The inner holder class is loaded only when getInstance() is called.
SingletonCls.java
public class SingletonCls {
private SingletonCls() {
}
private static class SingletonHolder {
private static final SingletonCls INSTANCE = new SingletonCls();
}
public static SingletonCls getInstance() {
return SingletonHolder.INSTANCE;
}
}
This approach is often preferred for class-based Singleton implementations because it is simple, lazy, and thread-safe under normal class-loading rules.
Singleton class in Java using enum type
Consider the following block of code:
public enum SingletonEnumEx {
INSTANCE;
}
Enum type SingletonEnumEx has an implicitly declared public static final field of type SingletonEnumEx for each constant declared in the body of SingletonEnumEx. In other words JVM considers the constant INSTANCE is of type SingletonEnumEx and also public static final. This is the behavior of class instance required by design of Singleton.
The enum members are explained clearly in the java doc here.
Java Compiler takes care of the implicit declaration and is thread safe.
Thus, using this behavior, Singleton Class could be achieved using enum as shown in the following example. Enum type for Singleton design.
SingletonEnumEx.java
/**
* Singleton Design implementation using enum
*/
public enum SingletonEnumEx {
// the variable INSTANCE shall be compiled to a public static final field of type SingletonEnumEx
INSTANCE;
private String message;
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
}
Class that uses SingletonEnumEx
ExamplePgm.java
/**
* Example class that uses Singleton class and its variables
*/
public class ExamplePgm {
public static void main(String[] args) {
System.out.println("Starting of ExamplePgm..");
// access instance of SingletonCls using getInstance() method
SingletonEnumEx.INSTANCE.setMessage("This message is set in main of ExamplePgm");
displayMsg();
}
public static void displayMsg(){
System.out.println(SingletonEnumEx.INSTANCE.getMessage());
}
}
Enum Singleton is concise and naturally gives one enum constant instance per JVM class loader. It also avoids many issues that can occur with reflection and serialization in ordinary class-based Singleton implementations.
Early loading vs lazy loading vs enum Singleton in Java
The following table summarizes when each Singleton implementation is suitable.
| Singleton approach | Object creation time | Thread-safe? | Best used when |
|---|---|---|---|
| Early loading | When the class is loaded | Yes, through class initialization | The instance is small or always needed |
| Lazy loading without synchronization | First call to getInstance() | No | Single-threaded code or learning example |
| Synchronized lazy loading | First call to getInstance() | Yes | Simple thread-safe lazy loading is required |
| Double-checked locking | First call to getInstance() | Yes, when implemented with volatile | Lazy loading is needed with less synchronization after initialization |
| Initialization-on-demand holder | First call to getInstance() | Yes | A clean lazy class-based Singleton is preferred |
| Enum Singleton | When the enum constant is initialized | Yes | A compact and robust Singleton is acceptable for the design |
Common mistakes in Java Singleton class implementation
- Leaving the constructor public: If the constructor is public, any class can create a new object, so the class is not a Singleton.
- Using lazy loading without thread safety in multi-threaded code: Two threads can create two different objects if the first null check is not protected.
- Storing too much mutable global state: A Singleton with many setters can make program flow hard to understand and test.
- Ignoring serialization: A serialized and deserialized class-based Singleton may create another object unless handled carefully. Enum Singleton avoids this common issue.
- Using Singleton where dependency injection is clearer: If the object must be mocked, configured, or replaced often, injecting a dependency is usually easier to maintain.
FAQs on Singleton Class in Java
What is Singleton class in Java?
A Singleton class in Java is a class that restricts object creation to one instance and provides a public way to access that same instance.
Is lazy loading Singleton thread-safe in Java?
Simple lazy loading Singleton is not thread-safe. In a multi-threaded program, more than one thread may create an instance. Use synchronization, double-checked locking with volatile, the holder idiom, or enum Singleton for thread-safe behavior.
Which Singleton implementation is preferred in Java?
For a class-based Singleton, the initialization-on-demand holder idiom is a clean option. If an enum suits the design, enum Singleton is also a robust and compact approach.
Why should the Singleton constructor be private?
The constructor is private so that other classes cannot create objects using new. This allows the Singleton class itself to control instance creation.
Can Singleton class in Java have methods and variables?
Yes. A Singleton can have fields and methods like any other Java class. However, mutable fields should be used carefully because they represent shared global state.
Conclusion
Concluding this Java Tutorial on Singleton Class in Java, we have seen early loading, lazy loading, thread-safe lazy loading, double-checked locking, initialization-on-demand holder idiom, and enum-based Singleton implementation. Choose the approach based on object creation cost, thread-safety requirements, and how the object will be tested and maintained.
TutorialKart.com