A Singleton class is a design pattern that restricts the instantiation of a class to one object instance throughout the program’s execution. This pattern is commonly used in scenarios where only one instance of a class is required to coordinate actions across the system, such as managing a shared resource or maintaining a global state.
Here’s a simple example of a Singleton class in Java:
public class Singleton {
// Private static variable to hold the single instance of the class
private static Singleton instance;
// Private constructor to prevent instantiation from outside the class
private Singleton() {
}
// Public static method to provide access to the single instance of the class
public static Singleton getInstance() {
// Lazy initialization: create the instance only when it’s requested for the first time
if (instance == null) {
instance = new Singleton();
}
return instance;
}
// Other methods and properties of the class…
}
To call the Singleton class and obtain its instance.public class Main {
public static void main(String[] args) {
// Call the static method to get the singleton instance
Singleton singletonInstance = Singleton.getInstance();
// Use the singleton instance as needed
// For example, you can call methods or access properties of the singleton instance
}
}
In this example, the Singleton class ensures that only one instance of the class is created by providing a static method getInstance()
to access the instance. The instance is lazily initialized, meaning it's created only when it's requested for the first time. Subsequent calls to getInstance()
return the same instance.
In a multi-threaded environment, special care must be taken when implementing the Singleton pattern to ensure that only one instance of the class is created, even when multiple threads are accessing the getInstance()
method concurrently. There are several approaches to implementing thread-safe Singleton in Java. Here are two common ones:
- Eager Initialization with Static Initialization Block: This approach initializes the Singleton instance eagerly when the class is loaded, ensuring thread safety. It’s suitable when the overhead of initializing the Singleton instance is acceptable.
public class Singleton {
private static final Singleton instance = new Singleton();
private Singleton() {
}
public static Singleton getInstance() {
return instance;
}
}
2. Lazy Initialization with Double-Checked Locking (DCL): This approach initializes the Singleton instance lazily, i.e., only when it’s requested for the first time. It uses double-checked locking to ensure thread safety and minimize the performance overhead.
public class Singleton {
private static volatile Singleton instance;
private Singleton() {
}
public static Singleton getInstance() {
if (instance == null) {
synchronized (Singleton.class) {
if (instance == null) {
instance = new Singleton();
}
}
}
return instance;
}
}
In this approach, the volatile
keyword ensures that changes made to the instance
variable are visible to all threads. The double-checked locking pattern ensures that synchronization only occurs when necessary, reducing the overhead of locking.