For working professionals
For fresh graduates
More
Talk to our experts. We are available 7 days a week, 9 AM to 12 AM (midnight)
Indian Nationals
Foreign Nationals
The above statistics depend on various factors and individual results may vary. Past performance is no guarantee of future results.
The student assumes full responsibility for all expenses associated with visas, travel, & related costs. upGrad does not .
Recommended Programs
1. Introduction
6. PyTorch
9. AI Tutorial
10. Airflow Tutorial
11. Android Studio
12. Android Tutorial
13. Animation CSS
16. Apex Tutorial
17. App Tutorial
18. Appium Tutorial
21. Armstrong Number
22. ASP Full Form
23. AutoCAD Tutorial
27. Belady's Anomaly
30. Bipartite Graph
35. Button CSS
39. Cobol Tutorial
46. CSS Border
47. CSS Colors
48. CSS Flexbox
49. CSS Float
51. CSS Full Form
52. CSS Gradient
53. CSS Margin
54. CSS nth Child
55. CSS Syntax
56. CSS Tables
57. CSS Tricks
58. CSS Variables
61. Dart Tutorial
63. DCL
65. DES Algorithm
83. Dot Net Tutorial
86. ES6 Tutorial
91. Flutter Basics
92. Flutter Tutorial
95. Golang Tutorial
96. Graphql Tutorial
100. Hive Tutorial
103. Install Bootstrap
107. Install SASS
109. IPv 4 address
110. JCL Programming
111. JQ Tutorial
112. JSON Tutorial
113. JSP Tutorial
114. Junit Tutorial
115. Kadanes Algorithm
116. Kafka Tutorial
117. Knapsack Problem
118. Kth Smallest Element
119. Laravel Tutorial
122. Linear Gradient CSS
129. Memory Hierarchy
133. Mockito tutorial
134. Modem vs Router
135. Mulesoft Tutorial
136. Network Devices
138. Next JS Tutorial
139. Nginx Tutorial
141. Octal to Decimal
142. OLAP Operations
143. Opacity CSS
144. OSI Model
145. CSS Overflow
146. Padding in CSS
148. Perl scripting
149. Phases of Compiler
150. Placeholder CSS
153. Powershell Tutorial
158. Pyspark Tutorial
161. Quality of Service
162. R Language Tutorial
164. RabbitMQ Tutorial
165. Redis Tutorial
166. Redux in React
167. Regex Tutorial
170. Routing Protocols
171. Ruby On Rails
172. Ruby tutorial
173. Scala Tutorial
175. Shadow CSS
178. Snowflake Tutorial
179. Socket Programming
180. Solidity Tutorial
181. SonarQube in Java
182. Spark Tutorial
189. TCP 3 Way Handshake
190. TensorFlow Tutorial
191. Threaded Binary Tree
196. Types of Queue
197. TypeScript Tutorial
198. UDP Protocol
202. Verilog Tutorial
204. Void Pointer
205. Vue JS Tutorial
206. Weak Entity Set
207. What is Bandwidth?
208. What is Big Data
209. Checksum
211. What is Ethernet
214. What is ROM?
216. WPF Tutorial
217. Wireshark Tutorial
218. XML Tutorial
The Singleton Design Pattern is a creational pattern that restricts a class to a single instance, ensuring that only one object of its kind ever exists. It provides a global point of access to this unique instance, which is crucial for managing shared resources like a database connection or a central logging service where multiple instances would be problematic.
To see how this is achieved, in this tutorial, we will explore the core structure of the Singleton Design Pattern in Java, C++ and C#, to examine various implementation methods, and discuss critical aspects like thread safety.
Step into the next chapter of your tech journey. Our Software Engineering Courses prepare you to excel beyond coding and capture high-impact opportunities.
The Singleton pattern is useful in scenarios where having multiple instances of a class could lead to issues or unnecessary resource consumption. Some common examples include Database connection, logging and configuration settings.
The Singleton pattern is typically used in situations where you need to ensure that only one instance of a class is created and that it can be accessed globally. Here are some scenarios where the Singleton pattern is commonly employed:
1. Database Connections: To carry out various actions when working with a database, it is frequently essential to create a connection. Multiple database connections might use a lot of resources and result in problems like connection pool exhaustion.
Want to fast-track your tech career? Our Software Engineering Courses equip you with the skills to innovate, lead, and seize the next big opportunity.
2. Caching: In applications that involve caching data, a Singleton pattern can be used to manage the cache instance. A single cache instance can be shared by different parts of the application, ensuring that the data remains consistent and reducing redundancy.
3. Logger: For monitoring and debugging purposes, logging is a crucial component of any application. You can create a single logger object that can be accessed by several application components by using the Singleton design. Logs are aggregated and consistent as a result.
4. Configuration Settings: Global configuration settings are often required in applications, such as application-wide settings or environment variables. Implementing these settings as a Singleton allows easy access to the configuration values from anywhere in the codebase.
5. Thread Pools: In multithreaded applications, managing thread pools with the Singleton design might be advantageous. It enables the application's various components to share a pool of threads for task execution, ensuring effective resource utilization.
6. GUI Components: In programmes that use graphical user interfaces (GUIs), there are times when you just need to build a single instance of a specific component, like a prominent window or a dialogue box.
The Singleton pattern typically involves the following characteristics:
Here's an example of a Singleton implementation in Java:
public class Singleton {
private static Singleton instance;
private Singleton() {
// Private constructor
}
public static Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
Implementation:
The Singleton pattern can be applied in numerous ways. The prior example used lazy initialization, where the instance is only created on the first call to getInstance(). But it can be difficult to get a 100% Singleton because there are so many things to take into account, like thread safety and avoiding serialization or cloning.
Achieving 100% Singletons:
1. Eager Initialization: In this approach, the instance is created eagerly at the time of class loading. It guarantees that the instance is always available, but it may consume resources even if it's not needed immediately.
2. Thread-Safe Initialization: To ensure thread safety, you can synchronize the getInstance() method or use double-checked locking. However, synchronization can impact performance.
Also Read: How To Create a Thread in Java? | Multithreading in Java
Lazy Initialization:
Lazy initialization means the instance is created only when it is needed. It can be implemented as shown in the previous example. However, this implementation is not thread-safe. To achieve thread safety, you can use synchronization or employ the double-checked locking technique.
Using Enums:
A more modern approach to implementing singletons is by using enums. Enum values are instantiated only once by the JVM, making them inherently singletons. Here's an example:
public enum Singleton {
INSTANCE;
// Singleton methods and attributes can be defined here
}
The classic implementation of the Singleton pattern involves lazy initialization of the instance. Here's an example:
public class Singleton {
private static Singleton instance;
private Singleton() {
// Private constructor
}
public static Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
Also Read: Complete Guide to Java Enum in Java: Types and Best Practices
To ensure thread safety and prevent multiple instances from being created, you can make the getInstance() method synchronized. Here's an example:
public class Singleton {
private static Singleton instance;
private Singleton() {
// Private constructor
}
public static synchronized Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
In the eager instantiation approach, the instance is created eagerly at the time of class loading, ensuring that it is always available. Here's an example:
public class Singleton {
private static final Singleton instance = new Singleton();
private Singleton() {
// Private constructor
}
public static Singleton getInstance() {
return instance;
}
}
The "Double Checked Locking" technique combines lazy initialization with synchronization to achieve both thread safety and performance. Here's an example:
public class Singleton {
private volatile static Singleton instance;
private Singleton() {
// Private constructor
}
public static Singleton getInstance() {
if (instance == null) {
synchronized (Singleton. class) {
if (instance == null) {
instance = new Singleton();
}
}
}
return instance;
}
}
The "Double Checked Locking" approach is considered the best practice for implementing the Singleton pattern as it provides both thread safety and efficient lazy initialization.
The Singleton pattern's early instantiation refers to the creation of the singleton instance during class loading. To put it another way, the instance is eagerly constructed before it is truly required. Here is a Java illustration:
public class Singleton {
private static final Singleton instance = new Singleton();
private Singleton() {
// Private constructor
}
public static Singleton getInstance() {
return instance;
}
}
The singleton instance is only produced when it is requested for the first time under the lazy singleton approach. To put it another way, the instance is haphazardly generated when it is truly required. Here is a Java illustration:
public class Singleton {
private static Singleton instance;
private Singleton() {
// Private constructor
}
public static Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
In situations when the Singleton instance is produced via class-loading processes, the classloader is crucial to the Singleton pattern. Classes are loaded into memory, and instances of those classes are created by the class loader.
Also Read: Java Classes and Objects
The Singleton instance is often created when the class loader loads the class. This guarantees that the instance will be accessible and available for the duration of the application. The class loader, which loads the class and controls its lifetime, ensures that just one instance of the Singleton class is produced.
The process of transforming an item into a byte stream, which may be saved in a file or sent over a network, is referred to as serialization. The opposite of recreating the object from the byte stream is deserialization.
Serialisation can have the following effects about the Singleton pattern:
One real-life example where the Singleton pattern can be applied is a logging system. A logging system is typically a centralized component that handles logging messages from various parts of an application. It's desirable to have a single instance of the logging system throughout the application to ensure consistent logging behavior and avoid creating multiple logging instances.
Here's a simplified example in Java:
public class Logger {
private static Logger instance;
private Logger() {
// Private constructor
}
public static synchronized Logger getInstance() {
if (instance == null) {
instance = new Logger();
}
return instance;
}
public void log(String message) {
// Logging implementation
System.out.println(message);
}
}
Here's a pseudocode representation of the Singleton pattern:
class Singleton
private static instance: Singleton
private constructor()
// Private constructor to prevent external instantiation
public static getInstance() : Singleton
if the instance is null
instance = new Singleton()
return instance
Below listed are some of the language specific codes:
1. Singleton Design Pattern JavaScript:
// Singleton using a closure and IIFE (Immediately Invoked Function Expression)
const Singleton = (function () {
let instance;
function createInstance() {
// Private variables and methods can be defined here
return {
// Public methods and attributes can be defined here
};
}
return {
getInstance: function () {
if (!instance) {
instance = createInstance();
}
return instance;
}
};
})();
// Usage
const singletonInstance1 = Singleton.getInstance();
const singletonInstance2 = Singleton.getInstance();
console.log(singletonInstance1 === singletonInstance2); // Output: true
2. Singleton Design Pattern Python:
class Singleton:
_instance = None
def __new__(cls):
if cls._instance is None:
cls._instance = super().__new__(cls)
# Initialization can be done here
return cls._instance
# Usage
singletonInstance1 = Singleton()
singletonInstance2 = Singleton()
print(singletonInstance1 is singletonInstance2) # Output: True
3. Singleton Design Pattern Java:
java
Copy code
public class Singleton {
private static Singleton instance;
private Singleton() {
// Private constructor
}
public static Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
// Usage
Singleton singletonInstance1 = Singleton.getInstance();
Singleton singletonInstance2 = Singleton.getInstance();
System.out.println(singletonInstance1 == singletonInstance2); // Output: true
4. Singleton Design Pattern C#:
public class Singleton
{
private static Singleton instance;
private Singleton()
{
// Private constructor
}
public static Singleton get instance()
{
if (instance == null)
{
instance = new Singleton();
}
return instance;
}
}
// Usage
Singleton singletonInstance1 = Singleton.GetInstance();
Singleton singletonInstance2 = Singleton.GetInstance();
Console.WriteLine(singletonInstance1 == singletonInstance2); // Output: True
5. Singleton Design Pattern C++:
class Singleton {
public:
static Singleton& get instance() {
static Singleton instance;
return instance;
}
// Other public methods and attributes can be defined here
private:
Singleton() {
// Private constructor
}
// Private copy constructor and assignment operator to prevent cloning
Singleton(const Singleton&) = delete;
Singleton& operator=(const Singleton&) = delete;
};
// Usage
Singleton& singletonInstance1 = Singleton::GetInstance();
Singleton& singletonInstance2 = Singleton::GetInstance();
cout << (&singletonInstance1 == &singletonInstance2) << endl; // Output: 1 (True)
6. Singleton Design Pattern PHP:
class Singleton {
private static $instance;
private function __construct() {
// Private constructor
}
public static function getInstance() {
if (!self::$instance) {
self::$instance = new self();
}
return self::$instance;
}
}
// Usage
$singletonInstance1 = Singleton::getInstance();
$singletonInstance2 = Singleton::getInstance();
echo ($singletonInstance1 === $singletonInstance2) ? 'true' : 'false'; // Output: true
In all the examples above, the Singleton pattern ensures that only one instance of the class is created and shared throughout the application. The static method getInstance() is used to access the single instance of the class.
Below listed are the pros and cons of Singleton design pattern example:
Pros:
Cons:
Singleton Pattern:
Flyweight Pattern:
The Singleton Design Pattern is a highly effective solution when you must guarantee that only one instance of a class is ever created. It provides a practical way to control object instantiation, improve the management of shared resources, and maintain a consistent state throughout your application.
By understanding both the strengths and weaknesses of the Singleton Design Pattern in Java, C++ and C#, such as its global accessibility versus potential challenges in unit testing, you can make more educated decisions when architecting your software and choosing the best patterns for your specific needs.
The Singleton Design Pattern is a foundational creational design pattern. Creational patterns are all about how objects are created, and Singleton is the most focused of them all. Its single, unwavering purpose is to ensure that a class has only one instance and provides a single, global point of access to that instance. The Singleton Design Pattern in Java is crucial for scenarios where managing a shared, unique resource is necessary, such as a single database connection, a logging service, or a configuration manager for an entire application.
The primary problem solved by the Singleton Design Pattern is the uncontrolled proliferation of objects that should be unique. Imagine an application needing to access a configuration file. If every part of the app creates its own configuration reader, you'd have multiple objects in memory holding the same data, leading to wasted resources and potential inconsistencies if one of them gets out of sync. The Singleton Design Pattern in Java elegantly solves this by creating a single, shared configuration object that all parts of the application can access, ensuring data consistency and efficient resource management.
The Singleton Design Pattern in Java offers several key advantages that make it a popular choice in certain contexts:
Despite its benefits, the Singleton Design Pattern is often criticized and can be considered an "anti-pattern" if misused. The primary disadvantages include:
Eager Initialization is the simplest way to create a Singleton Design Pattern in Java. In this approach, the single instance is created at the time the class is loaded by the JVM, not when it is first requested. This is done by creating a private static final instance of the class itself.
Advantages: It's incredibly simple and inherently thread-safe because the JVM handles the static field initialization during class loading.
Disadvantages: The instance is created even if the application never uses it, which can be a waste of resources.
The Singleton Design Pattern implemented this way is a great starting point for beginners.
Java
public class EagerSingleton {
// 1. Create the single instance at class loading time.
private static final EagerSingleton instance = new EagerSingleton();
// 2. Make the constructor private so it cannot be instantiated from outside.
private EagerSingleton() {}
// 3. Provide a global access point to the instance.
public static EagerSingleton getInstance() {
return instance;
}
}
Lazy Initialization is an alternative strategy for implementing the Singleton Design Pattern. Unlike Eager Initialization, this method defers the creation of the instance until the first time it is actually needed (when the getInstance() method is called). This is useful for resource-intensive singletons that may not even be used during an application's run. However, the simplest form of the Singleton Design Pattern in Java using lazy initialization is not thread-safe.
Java
public class LazySingleton {
private static LazySingleton instance;
private LazySingleton() {}
// The instance is created only when this method is called for the first time.
public static LazySingleton getInstance() {
if (instance == null) {
instance = new LazySingleton();
}
return instance;
}
}
The classic implementation of the Singleton Design Pattern without any synchronization is not thread-safe. If two threads call the getInstance() method of a lazy-initialized singleton at the exact same time when the instance is null, both threads might pass the if (instance == null) check. Consequently, both threads would create a new object, violating the core principle of the pattern. However, as taught in upGrad's advanced Java modules, thread safety for the Singleton Design Pattern in Java can be achieved by using synchronization, double-checked locking, or other thread-safe mechanisms.
The most straightforward way to make the lazy Singleton Design Pattern in Java thread-safe is by synchronizing the getInstance() method. By adding the synchronized keyword, you ensure that only one thread can execute this method at a time. This solves the thread-safety problem but introduces a performance penalty, as the lock is acquired every time the method is called, even after the instance has been created. This is a common trade-off when implementing a thread-safe Singleton Design Pattern.
Java
public class ThreadSafeSingleton {
private static ThreadSafeSingleton instance;
private ThreadSafeSingleton() {}
// The 'synchronized' keyword makes this method thread-safe.
public static synchronized ThreadSafeSingleton getInstance() {
if (instance == null) {
instance = new ThreadSafeSingleton();
}
return instance;
}
}
Double-Checked Locking (DCL) is an optimization technique used to reduce the overhead of the synchronized method in a thread-safe Singleton Design Pattern. The goal is to avoid locking every time the getInstance() method is called. It works by checking the instance variable twice: once without a lock and, if it's null, a second time inside a synchronized block. For this to work correctly in modern Java, the instance variable must be declared volatile. The Singleton Design Pattern in Java using DCL is complex and was broken in older versions of Java (before Java 5), but it's a popular interview topic.
Java
public class DCLSingleton {
// The volatile keyword ensures visibility of changes across threads.
private static volatile DCLSingleton instance;
private DCLSingleton() {}
public static DCLSingleton getInstance() {
if (instance == null) { // First check (not synchronized)
synchronized (DCLSingleton.class) {
if (instance == null) { // Second check (synchronized)
instance = new DCLSingleton();
}
}
}
return instance;
}
}
The Bill Pugh implementation is a clever and highly recommended approach to creating a thread-safe Singleton Design Pattern in Java. It leverages an inner static helper class to achieve lazy initialization without requiring any synchronized blocks. The JVM only loads the inner class when the getInstance() method is called, and because it's a static class, the initialization is guaranteed to be thread-safe by the JVM itself. This elegant solution for the Singleton Design Pattern is both lazy and thread-safe with no performance overhead, making it the preferred choice for most scenarios.
Java
public class BillPughSingleton {
private BillPughSingleton() {}
// The inner static class is not loaded until getInstance() is called.
private static class SingletonHelper {
private static final BillPughSingleton INSTANCE = new BillPughSingleton();
}
public static BillPughSingleton getInstance() {
return SingletonHelper.INSTANCE;
}
}
Yes, and it's often considered the best and most robust method. Using an enum is the most concise way to implement the Singleton Design Pattern in Java. An enum is inherently a singleton because the JVM guarantees that any enum constant will be instantiated only once in an application. Additionally, it provides built-in protection against complex serialization and reflection attacks, which can be used to break other singleton implementations. As Joshua Bloch wrote in his book Effective Java, for a thread-safe and serialization-proof Singleton Design Pattern, "a single-element enum is often the best way."
Java
public enum EnumSingleton {
INSTANCE;
// You can add methods here
public void doSomething() {
System.out.println("Enum Singleton is doing something!");
}
}
// To use it: EnumSingleton.INSTANCE.doSomething();
When a class implementing the Singleton Design Pattern is serialized and then deserialized, the deserialization process creates a new object, thus violating the singleton principle. This is a subtle but critical vulnerability. To prevent this, you must implement the readResolve() method in your singleton class. The JVM calls this method during deserialization and uses the return value as the final deserialized object. By returning your original instance from this method, you ensure that the Singleton Design Pattern in Java remains intact.
Java
import java.io.Serializable;
public class SerializableSingleton implements Serializable {
private static final SerializableSingleton instance = new SerializableSingleton();
private SerializableSingleton() {}
public static SerializableSingleton getInstance() {
return instance;
}
// This method is the key to preserving the singleton on deserialization.
protected Object readResolve() {
return getInstance();
}
}
Yes, it is possible to create multiple instances of a Singleton Design Pattern using reflection. The Reflection API in Java allows you to inspect and manipulate classes at runtime, including accessing their private members. An attacker could use reflection to get a handle on the private constructor and use constructor.setAccessible(true) to make it public, and then call it to create new instances. While this requires explicit and intentional manipulation, it is a known way to break the Singleton Design Pattern in Java. The enum singleton implementation is immune to this attack.
If your singleton class implements the Cloneable interface, it's possible for a client to call the clone() method to create a copy of your singleton object, which again violates the pattern. To protect the Singleton Design Pattern from this, you should override the clone() method and throw a CloneNotSupportedException from it. This prevents anyone from creating a copy. Alternatively, you could have the clone() method return the original instance. For a robust Singleton Design Pattern in Java, considering such edge cases is crucial.
Java
public class CloneableSingleton implements Cloneable {
private static final CloneableSingleton instance = new CloneableSingleton();
private CloneableSingleton() {}
public static CloneableSingleton getInstance() {
return instance;
}
@Override
protected Object clone() throws CloneNotSupportedException {
throw new CloneNotSupportedException("Cloning of this singleton is not allowed.");
}
}
Yes, just like other classes, a Singleton Design Pattern class can be subclassed. The subclass will not, however, adhere to the singleton principle by default because, if not carefully designed, it can have multiple instances. The private constructor of the parent singleton is not inherited, so the child class can define its own constructor. If you want to maintain the singleton contract in the child class, you must reimplement the entire logic of the Singleton Design Pattern in Java within the subclass, which is often a sign of a flawed design.
This is a common point of confusion. A static class in Java is a class that only contains static methods and cannot be instantiated at all (you typically make its constructor private). The Singleton Design Pattern, on the other hand, allows for the creation of exactly one instance of the class.
Key differences:
Choosing between a static utility class and the Singleton Design Pattern in Java depends on whether you need to maintain state in an actual object.
While the Singleton Design Pattern provides a global access point, which is similar to a global variable, it offers more control and flexibility. A global variable can be created and modified by any part of the code at any time, which can lead to a chaotic state. The Singleton Design Pattern in Java, however, encapsulates its own creation and ensures that initialization logic is handled correctly (e.g., lazy initialization, thread safety). It provides a controlled, single entry point to a unique resource, which is a more structured approach than a simple public static variable.
You should be very cautious and avoid the Singleton Design Pattern in several situations, as it can do more harm than good:
The Singleton Design Pattern is one of the most debated patterns, and many experienced developers consider it an "anti-pattern" in modern software development. The primary reasons are the disadvantages mentioned earlier: it creates global state, makes code hard to test, and violates principles like Single Responsibility and Dependency Inversion. While it has valid use cases (e.g., loggers, hardware access), overusing the Singleton Design Pattern in Java often leads to rigid and unmaintainable code. Learning about its pitfalls is just as important as learning how to implement it, a philosophy we hold strongly at upGrad.
There is no single "best" implementation, as the choice depends on the specific requirements of your application. However, here's a general guideline for choosing a Singleton Design Pattern implementation:
Understanding these different approaches to the Singleton Design Pattern in Java allows you to select the most appropriate one for your project.
FREE COURSES
Start Learning For Free
Author|900 articles published