Java Singleton and Synchronization
Object-Oriented Design practice on Codemia
Turn requirements into classes, and defend the design, on the problems that come up in OOD rounds.
Java's Singleton design pattern is a powerful construct for creating a single instance of a class to be used throughout an application. It's a common design pattern used to ensure that a particular class has only one instance and to provide a global access point to that instance. When discussing Singletons, synchronization is an important aspect, particularly in a multi-threaded environment, to maintain its uniqueness. In this article, we'll discuss Java Singleton patterns and synchronization strategies in detail.
Java Singleton Design Pattern
A Singleton class in Java restricts the instantiation of a class and ensures that one and only one instance of the class exists at any point in time. This is particularly useful when managing shared resources or configurations. There are a few common implementations of the Singleton pattern in Java:
1. Eager Initialization
Eager initialization involves creating the singleton instance at the time of class loading. This approach is simple but doesn't allow for exception handling during instance creation.
2. Lazy Initialization
Lazy initialization defers the creation of the singleton instance until it is first requested. This can be efficient if the instance is not used until needed.
Note: The lazy initialization above is not thread-safe, which leads us to consider synchronization in Singleton design.
Synchronization in Singleton Pattern
In a multi-threaded environment, the Singleton pattern must be thread-safe. Without synchronization, multiple threads could create multiple instances of the Singleton class. Here are several strategies for ensuring thread safety:
1. Thread-Safe Singleton with Synchronized Method
One way to make the Singleton lazy initialization thread-safe is to synchronize the getInstance() method.
Drawback: This approach significantly reduces performance because of the additional overhead of acquiring the lock every time the method is called.
2. Double-Checked Locking
Double-checked locking reduces the performance overhead by first checking whether the instance is null before acquiring the lock.
In this approach, the volatile keyword ensures that multiple threads handle the unique instance variable correctly when it is initialized to the DoubleCheckedLockingSingleton instance.
3. Bill Pugh Singleton Design
This technique leverages the class loader mechanism of Java to create the Singleton class. The instance is created in a static inner class only when it is first requested.
This is considered one of the best practices for creating a Singleton in Java due to its performance benefits and simplicity.
Table Summarizing Singleton Implementation Strategies
| Strategy | Description | Synchronization | Performance Impact |
| Eager Initialization | Instance is created at class loading time. | No | No lazy loading, instance is created even if never used. |
| Lazy Initialization | Instance is created only when needed. | No | Not thread-safe in a multi-threaded environment. |
| Synchronized Method | Synchronization ensures thread safety by locking on every call. | Full | High performance impact due to locking every call to getInstance(). |
| Double-Checked Locking | Reduces the use of synchronization by checking a condition before locking. | Partial | Performance benefit as locking is called only during the first call. Requires Java 5+ due to volatile. |
| Bill Pugh's Inner Class | Inner static class provides a unique and thread-safe solution by using Java's inherent class loader mechanism. | Yes | No performance costs after the class is loaded, as locking is not used. |
Conclusion
The Singleton design pattern is essential for controlling object creation, ensuring that a class has no more than one instance. In concurrent applications, synchronization mechanisms become crucial to maintain instance uniqueness. Each Singleton implementation strategy offers different trade-offs in terms of performance and complexity. Choosing the appropriate Singleton pattern depends on the use case and application requirements.
Related reading
- Jersey stopped working with InjectionManagerFactory not found
- Limitation with classes derived from generic classes in swift
- make arrayList.toArray return more specific types
- Making certain methods visible only to particular packages
- Java Synchronized Block for .class
- Java synchronized method
- Java Sorting an array based on another array with indexOf method
- Java splitting a comma-separated string but ignoring commas in quotes

OOD Fundamentals
Master object-oriented design from first principles, SOLID, design patterns, and classic interview problems with hands-on coding.
View the courseTrack what you have practised
A free account saves your progress, solutions and study plan across every problem on Codemia.
Object-Oriented Design practice on Codemia
Turn requirements into classes, and defend the design, on the problems that come up in OOD rounds.