- 1Java OOP Introduction
- 2Java Class
- 3Java Class Constructor
- 4Java Class Objects
- 5Java Access Modifiers
- 6Java Static Variables in Classes
- 7Java Static Methods Explained
- 8Java Static Blocks
- 9Java final Variables
- 10Java final Methods
- 11Java final class
- 12Inheritance in Java
- 13Java Method Overriding
- 14Java Abstraction in OOP
- 15Interfaces in Java
- 16Polymorphism in Java
- 17Encapsulation in Java
- 18Java Nested Classes
- 19Java Nested Static Class
- 20Java Anonymous Class
- 21Java Singleton Class
- 22Java Enums
- 23Reflection in Java
Java Singleton Class
What, Why and How to Use It
In Java, a Singleton class is a class that allows only one instance of itself to be created—and gives access to that single instance. It’s a widely used design pattern, especially when you need exactly one object to coordinate actions across the system.
Why Use a Singleton?
Imagine you're logging actions throughout your application. Would you want multiple loggers writing randomly? Of course not. A singleton logger ensures consistent behavior and state—no matter where it’s used.
- Ensures controlled access to shared resources
- Saves memory by avoiding multiple instances
- Promotes centralized management (e.g., database connectors, config managers)
How to Implement a Singleton Class in Java
Let’s go through different ways to implement a singleton class. Each method has its own nuances, especially in multi-threaded environments.
1. Eager Initialization
The instance is created at the time of class loading.
public class EagerSingleton {
private static final EagerSingleton instance = new EagerSingleton();
private EagerSingleton() {
System.out.println("Instance created");
}
public static EagerSingleton getInstance() {
return instance;
}
}
Usage
public class Main {
public static void main(String[] args) {
EagerSingleton obj1 = EagerSingleton.getInstance();
EagerSingleton obj2 = EagerSingleton.getInstance();
System.out.println(obj1 == obj2); // true
}
}
Instance created
true
Explanation
Only one object is created. Even if we try to get the instance multiple times, we get the same reference.
2. Lazy Initialization
In this approach, the instance is created only when it’s needed.
public class LazySingleton {
private static LazySingleton instance;
private LazySingleton() {}
public static LazySingleton getInstance() {
if (instance == null) {
instance = new LazySingleton();
System.out.println("Instance created");
}
return instance;
}
}
Usage
public class Main {
public static void main(String[] args) {
LazySingleton obj1 = LazySingleton.getInstance();
LazySingleton obj2 = LazySingleton.getInstance();
System.out.println(obj1 == obj2); // true
}
}
Instance created
true
Explanation
The object is created only when getInstance()
is called the first time. It saves resources but is not thread-safe.
3. Thread-Safe Singleton (Synchronized Method)
This method ensures thread safety using synchronization.
public class ThreadSafeSingleton {
private static ThreadSafeSingleton instance;
private ThreadSafeSingleton() {}
public static synchronized ThreadSafeSingleton getInstance() {
if (instance == null) {
instance = new ThreadSafeSingleton();
System.out.println("Instance created");
}
return instance;
}
}
Explanation
The synchronized
keyword ensures that only one thread can execute this method at a time. It's safe, but might reduce performance due to synchronization overhead.
4. Double-Checked Locking (Efficient Thread-Safety)
This is a more efficient way of making the singleton thread-safe.
public class DoubleCheckedSingleton {
private static volatile DoubleCheckedSingleton instance;
private DoubleCheckedSingleton() {}
public static DoubleCheckedSingleton getInstance() {
if (instance == null) {
synchronized (DoubleCheckedSingleton.class) {
if (instance == null) {
instance = new DoubleCheckedSingleton();
System.out.println("Instance created");
}
}
}
return instance;
}
}
5. Singleton Using Enum (Best Practice)
Using Enum is the simplest and most effective way to implement a singleton in Java. It prevents reflection and serialization issues.
public enum EnumSingleton {
INSTANCE;
public void show() {
System.out.println("Singleton using Enum");
}
}
Usage
public class Main {
public static void main(String[] args) {
EnumSingleton singleton = EnumSingleton.INSTANCE;
singleton.show();
}
}
Singleton using Enum
Common Mistakes to Avoid
- Leaving constructor public or protected
- Ignoring thread safety in multi-threaded applications
- Using reflection to break singleton (use Enum to prevent this)
Where is Singleton Used?
Singleton pattern is used across frameworks and applications:
- Database connections
- Logger classes
- Configuration managers
- File handlers