
The Java Singleton Pattern is a creational design pattern that restricts a class to a single instance per Java Virtual Machine and exposes that instance through a global access point. It originates from the Gang of Four book Design Patterns (1994) and remains one of the most widely used patterns for managing shared resources such as logging, configuration, connection pools, and caches.
This guide covers seven implementation variants in Java: eager initialization, static block initialization, lazy initialization, synchronized method, double-checked locking, Bill Pugh, and enum singleton. It also covers the two attack vectors that can break the singleton guarantee, reflection and serialization, with prevention strategies for each. The final sections compare Singleton with static utility classes, explain how dependency injection frameworks such as Spring replace manual Singleton implementation, and cover Singleton behavior under virtual threads and GraalVM native image.
volatile keyword to prevent the JVM from publishing a partially constructed instance.ApplicationContext, which removes the need to implement the Singleton pattern manually in most modern Java applications.The Singleton pattern is a creational design pattern that guarantees a class has exactly one instance per JVM and exposes a global access point to retrieve it. It is used when one shared object must coordinate behavior across an application, such as a logger, configuration manager, or connection pool. The pattern is also used internally by the JDK in classes such as java.lang.Runtime and java.awt.Desktop.
Every Singleton implementation in Java shares three structural elements:
new.getInstance().The Singleton pattern is also used as a building block in other Java design patterns, including Abstract Factory, Builder, Prototype, and Facade.
Avoid Singleton when it introduces problems that outweigh its benefits:
Singleton.getInstance() internally declares no dependency in its constructor. The collaborator is invisible to the caller, which makes the class harder to reason about and impossible to rewire without editing source code.getInstance() always returns the live instance, you cannot substitute a mock or a test double without either modifying the Singleton class itself or using a bytecode manipulation library. Classes that depend on a Singleton directly are effectively untestable in isolation.In modern Java applications, dependency injection with Spring or Guice is the preferred alternative for most use cases that historically relied on a manual Singleton.
Use eager initialization when your Singleton is lightweight, has no constructor dependencies on runtime state, and will always be needed during the lifetime of the application. It is the correct default for simple shared resources such as a stateless utility wrapper or an application-wide constant registry. Avoid it when the object is heavyweight or when its constructor reads environment variables, opens file handles, or establishes network connections.
In eager initialization, the singleton instance is created when the class is loaded by the JVM. The instance exists before any code calls getInstance(), regardless of whether the application ever uses it. The JVM guarantees that class loading runs exactly once per classloader and is thread-safe, so no synchronization keyword is needed in the implementation.
package com.journaldev.singleton;
public class EagerInitializedSingleton {
// Instance is created at class load time and assigned exactly once
private static final EagerInitializedSingleton instance = new EagerInitializedSingleton();
// Private constructor blocks external instantiation via `new`
private EagerInitializedSingleton(){}
// Global access point; returns the pre-created instance
public static EagerInitializedSingleton getInstance() {
return instance;
}
}
Eager initialization is the simplest Singleton implementation in Java. The JVM guarantees that class initialization runs exactly once and is thread-safe, so no synchronization is needed.
Advantages:
Limitations:
getInstance(), which wastes memory for heavyweight objects.Use static block initialization when your Singleton constructor can fail. Eager initialization does not allow the constructor to throw a checked exception because there is no try/catch wrapping the field initializer. If your Singleton reads a configuration file, opens a socket, or loads a native library during construction, a static block gives you a place to catch the failure and convert it to a RuntimeException that halts class loading with a clear error rather than leaving the application in a partially initialized state.
Static block initialization is structurally identical to eager initialization in every other respect: the instance is created at class load time, it is thread-safe by the JVM class loading guarantee, and it is not lazy.
package com.journaldev.singleton;
public class StaticBlockSingleton {
private static StaticBlockSingleton instance;
private StaticBlockSingleton(){}
// Static block runs once at class load; wraps construction in try/catch
static {
try {
instance = new StaticBlockSingleton();
} catch (Exception e) {
// Convert any checked exception into RuntimeException so class loading fails fast
throw new RuntimeException("Exception occurred in creating singleton instance");
}
}
public static StaticBlockSingleton getInstance() {
return instance;
}
}
Use static block initialization when the Singleton constructor may fail with a checked exception (for example, while reading configuration from disk or initializing a network resource). Both approaches load the instance eagerly, so neither is appropriate for heavyweight resources that should be created lazily.
Lazy initialization defers Singleton creation until the first call to getInstance(). The instance is not created at class load time, which is appropriate for heavyweight Singletons that may not be needed in every program run.
package com.journaldev.singleton;
public class LazyInitializedSingleton {
private static LazyInitializedSingleton instance;
private LazyInitializedSingleton(){}
public static LazyInitializedSingleton getInstance() {
// Race condition exposure: multiple threads can pass this check simultaneously
if (instance == null) {
instance = new LazyInitializedSingleton();
}
return instance;
}
}
Warning: This implementation is not thread-safe and breaks the Singleton guarantee under concurrent access. Use it only in confirmed single-threaded contexts.
Two threads can interleave inside the null check and produce two distinct instances:
instance == null. Result: true.instance == null before Thread A finishes constructing the object. Result: true.new LazyInitializedSingleton().The next sections cover four thread-safe alternatives, ordered from highest synchronization cost to lowest.
If you need lazy initialization and thread safety and you are not concerned about performance under high concurrency, marking getInstance() as synchronized is the simplest correct solution. Only one thread can enter the method at a time, which closes the race condition described in the previous section. The trade-off is that every call to getInstance() acquires a monitor lock, even the millions of calls that happen after the instance has already been created. For applications where getInstance() is called infrequently, this overhead is irrelevant. For hot paths called by thousands of threads per second, use Bill Pugh instead.
package com.journaldev.singleton;
public class ThreadSafeSingleton {
private static ThreadSafeSingleton instance;
private ThreadSafeSingleton(){}
// synchronized serializes all callers; only one thread enters the method at a time
public static synchronized ThreadSafeSingleton getInstance() {
if (instance == null) {
instance = new ThreadSafeSingleton();
}
return instance;
}
}
Every call to synchronized getInstance() acquires the class monitor, which involves a compare-and-swap on the lock word and a memory barrier. This cost is paid on every call, including the millions of calls that happen after the instance has already been created and the lock no longer serves any purpose. Under contention, all callers serialize on the monitor and throughput collapses. Double-checked locking solves this by synchronizing only during the brief window when the instance is being created, after which subsequent calls perform a single volatile read.
Double-checked locking checks instance == null twice: once outside the synchronized block to avoid the lock when the instance already exists, and once inside the synchronized block to prevent two threads from both creating the instance after passing the first check.
Object construction in the JVM happens in three steps: (1) allocate memory, (2) run the constructor to initialize fields, (3) assign the reference to instance. Without volatile, the JVM or the CPU is allowed to reorder steps 2 and 3. A second thread can then read a non-null instance reference that points to a partially constructed object.
Declaring the instance variable volatile prevents this reordering and establishes a happens-before relationship between the write and any subsequent read across threads.
package com.journaldev.singleton;
public class DoubleCheckedLockingSingleton {
// volatile ensures visibility across threads and prevents instruction reordering
private static volatile DoubleCheckedLockingSingleton instance;
private DoubleCheckedLockingSingleton() {}
public static DoubleCheckedLockingSingleton getInstance() {
// First check: avoid acquiring the lock if the instance is already created
if (instance == null) {
// Synchronize only during the brief initialization window
synchronized (DoubleCheckedLockingSingleton.class) {
// Second check: prevent duplicate creation if two threads passed the first check
if (instance == null) {
instance = new DoubleCheckedLockingSingleton();
}
}
}
return instance;
}
}
Note: This guarantee depends on the Java 5+ memory model defined by JSR-133. On JDKs prior to Java 5, double-checked locking was broken even with volatile.
Under JSR-133, a write to a volatile variable happens-before any subsequent read of that variable across threads. The JVM is required to publish the fully constructed object before any thread observes the non-null reference, so no thread can ever see a partially initialized instance through the volatile field.
Continue your learning with Java Thread Safety.
The Bill Pugh Singleton, also known as the initialization-on-demand holder idiom, uses an inner static helper class to defer instance creation until first access without any explicit synchronization. The pattern was proposed by Bill Pugh as a response to the unreliability of double-checked locking under the pre-Java 5 memory model.
package com.journaldev.singleton;
public class BillPughSingleton {
private BillPughSingleton(){}
// Inner static class is not loaded until referenced for the first time
private static class SingletonHelper {
// INSTANCE is created when SingletonHelper is initialized by the JVM
private static final BillPughSingleton INSTANCE = new BillPughSingleton();
}
public static BillPughSingleton getInstance() {
// First reference to SingletonHelper triggers its class initialization
return SingletonHelper.INSTANCE;
}
}
SingletonHelper is not loaded when BillPughSingleton is loaded. The JVM loads it only when getInstance() is called for the first time, at which point class initialization runs and INSTANCE is created. Class initialization is inherently thread-safe because the JVM acquires an internal lock for the duration of class initialization, so no synchronized block or volatile field is required.
The Bill Pugh implementation removes the synchronization complexity and overhead of double-checked locking:
synchronized block at the call site.volatile field.Bill Pugh is the recommended general-purpose Singleton implementation when lazy loading is required.
The enum Singleton declares a single-value enum type whose sole constant serves as the singleton instance. The JVM guarantees that the constant is instantiated exactly once and provides built-in protection against both reflection and serialization attacks. Joshua Bloch recommends this approach in Effective Java (Item 3).
package com.journaldev.singleton;
public enum EnumSingleton {
// INSTANCE is the sole enum constant and the singleton instance
INSTANCE;
// Instance fields are safe to add; each enum constant gets its own copy
private String databaseUrl = "jdbc:postgresql://localhost:5432/appdb";
private int maxConnections = 10;
public String getDatabaseUrl() {
return databaseUrl;
}
public void setDatabaseUrl(String url) {
// In production, guard writes with validation or make the field final
this.databaseUrl = url;
}
public int getMaxConnections() {
return maxConnections;
}
}
External code accesses the singleton through the enum constant:
// Retrieve the singleton and read configuration
String url = EnumSingleton.INSTANCE.getDatabaseUrl();
int maxConn = EnumSingleton.INSTANCE.getMaxConnections();
// Update configuration at runtime
EnumSingleton.INSTANCE.setDatabaseUrl("jdbc:postgresql://prod-host:5432/appdb");
Three properties make enum singleton the safest implementation:
Constructor.newInstance() on an enum throws IllegalArgumentException.readObject(). No readResolve() is needed.Enum singleton is the recommended Singleton implementation in all cases where lazy initialization is not required.
java.lang.Enum and cannot extend any other class. They can implement interfaces.A Singleton and a class with only static members both provide a single point of access to shared state, but they differ in capability and intent.
| Characteristic | Singleton | Static Class |
|---|---|---|
| Instantiation | Single instance, created on demand or at load | No instantiation; static members only |
| Interface implementation | Yes | No |
| Inheritance | Can extend a superclass | Cannot extend a class (implicitly final in effect) |
| Lazy initialization | Supported (Bill Pugh, double-checked locking) | Not applicable |
| Serialization | Supported with readResolve() |
Not applicable |
| Testability | Can be mocked when injected as a dependency | Difficult to mock |
| State | Encapsulated in instance | Shared via static fields |
| Polymorphism | Supported | Not supported |
Use a Singleton when the object holds state, must implement an interface for abstraction, may need lazy loading, or must be replaced with a mock during unit testing.
Use a static class when the API is a stateless utility with no instance lifecycle and no need for polymorphism. Examples in the JDK are java.util.Collections and java.util.Arrays.
Reflection can break every Singleton implementation except enum by accessing the private constructor at runtime. Enum singleton is immune at the JVM level.
Warning: Reflection bypasses the private access modifier on the constructor and breaks the Singleton guarantee on eager, static block, lazy, synchronized, double-checked locking, and Bill Pugh implementations.
package com.journaldev.singleton;
import java.lang.reflect.Constructor;
public class ReflectionSingletonTest {
public static void main(String[] args) {
EagerInitializedSingleton instanceOne = EagerInitializedSingleton.getInstance();
EagerInitializedSingleton instanceTwo = null;
try {
Constructor[] constructors = EagerInitializedSingleton.class.getDeclaredConstructors();
for (Constructor constructor : constructors) {
// setAccessible(true) bypasses the private modifier on the constructor
constructor.setAccessible(true);
// newInstance() creates a second instance, breaking the singleton guarantee
instanceTwo = (EagerInitializedSingleton) constructor.newInstance();
break;
}
} catch (Exception e) {
e.printStackTrace();
}
System.out.println(instanceOne.hashCode());
System.out.println(instanceTwo.hashCode());
}
}
The two printed hash codes will differ, which confirms that two distinct instances exist. The exact values vary per JVM run.
Add a guard check in the private constructor that throws when an instance already exists:
private EagerInitializedSingleton() {
// Block reflective instantiation after the singleton is created
if (instance != null) {
throw new IllegalStateException(
"Singleton instance already exists. Use getInstance() instead."
);
}
}
This guard works for eager and static block initialization because instance is non-null by the time any reflection call runs. It does not work reliably for lazy implementations because instance is null during the first legitimate construction, which means a reflection call that races with getInstance() can still succeed.
For full protection against reflection attacks, use enum singleton. The JVM rejects Constructor.newInstance() calls on enum types with IllegalArgumentException, which is the only approach immune to reflection at the JVM level. Continue your learning with the Java Reflection Tutorial.
A Singleton that implements Serializable can be written to and read from a file or network stream. This support is required in many distributed systems, but it introduces a second attack vector that breaks the Singleton guarantee.
Warning: Java’s default deserialization mechanism bypasses the constructor and creates a new object instance. Without an explicit fix, every readObject() call returns a fresh instance and breaks the Singleton guarantee.
package com.journaldev.singleton;
import java.io.Serializable;
public class SerializedSingleton implements Serializable {
private static final long serialVersionUID = -7604766932017737115L;
private SerializedSingleton(){}
private static class SingletonHelper {
private static final SerializedSingleton instance = new SerializedSingleton();
}
public static SerializedSingleton getInstance() {
return SingletonHelper.instance;
}
}
The following test serializes the singleton, deserializes it, and prints both hash codes:
package com.journaldev.singleton;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectInputStream;
import java.io.ObjectOutput;
import java.io.ObjectOutputStream;
public class SingletonSerializedTest {
public static void main(String[] args) throws FileNotFoundException, IOException, ClassNotFoundException {
SerializedSingleton instanceOne = SerializedSingleton.getInstance();
ObjectOutput out = new ObjectOutputStream(new FileOutputStream(
"filename.ser"));
out.writeObject(instanceOne);
out.close();
// Default deserialization bypasses the constructor and creates a new instance
ObjectInput in = new ObjectInputStream(new FileInputStream(
"filename.ser"));
SerializedSingleton instanceTwo = (SerializedSingleton) in.readObject();
in.close();
System.out.println("instanceOne hashCode="+instanceOne.hashCode());
System.out.println("instanceTwo hashCode="+instanceTwo.hashCode());
}
}
The two printed hash codes will differ, which confirms that deserialization produced a second instance. The exact values vary per JVM run.
Add readResolve() as an instance method directly inside the outer Singleton class, not inside SingletonHelper. The JVM calls this method on the deserialized object immediately after construction and substitutes its return value, discarding the freshly created object:
package com.journaldev.singleton;
import java.io.Serializable;
public class SerializedSingleton implements Serializable {
private static final long serialVersionUID = -7604766932017737115L;
private SerializedSingleton(){}
private static class SingletonHelper {
private static final SerializedSingleton instance = new SerializedSingleton();
}
public static SerializedSingleton getInstance() {
return SingletonHelper.instance;
}
// readResolve() is called by the JVM after deserialization; returning getInstance()
// causes the JVM to discard the deserialized object and return the existing instance
protected Object readResolve() {
return getInstance();
}
}
After adding readResolve(), the two printed hash codes will match, which confirms that deserialization returned the existing instance.
Enum singleton handles this case automatically without requiring readResolve(), because the JVM’s enum deserialization always returns the existing constant. For background on the underlying APIs, see Java Serialization and Java Deserialization.
Most modern Java applications use a dependency injection container instead of implementing the Singleton pattern manually. The container manages the single instance and injects it into every collaborator that needs it.
In Spring, every bean is singleton-scoped by default within an ApplicationContext. Annotating a class with @Service, @Component, or @Repository is sufficient.
import org.springframework.stereotype.Service;
@Service
// Spring manages exactly one instance of this class per ApplicationContext
public class ConfigurationService {
public String getDatabaseUrl() {
return "jdbc:postgresql://localhost:5432/mydb";
}
}
The scope is per ApplicationContext, not per JVM. A single JVM that bootstraps two contexts will create two instances of the bean. This differs from the Singleton pattern’s JVM-level guarantee, but it matches what real applications need: per-application isolation rather than process-wide global state.
Manual singletons cannot be replaced with mocks in unit tests without modifying the class under test. Constructor injection eliminates this problem.
// Inject the service rather than calling ConfigurationService.getInstance()
public class DatabaseConnector {
private final ConfigurationService configService;
// Constructor injection allows passing a mock in unit tests
public DatabaseConnector(ConfigurationService configService) {
this.configService = configService;
}
// Delegates to the injected service; no static getInstance() call in the method body
public String getDatabaseUrl() {
return configService.getDatabaseUrl();
}
}
Constructor injection with Spring or Guice removes the need for a manual Singleton implementation in most production Java applications and produces classes that are testable in isolation.
The following JUnit 5 and Mockito example shows what a test for DatabaseConnector looks like when the dependency is injected rather than fetched via getInstance():
import org.junit.jupiter.api.Test;
import org.mockito.Mockito;
import static org.junit.jupiter.api.Assertions.assertEquals;
public class DatabaseConnectorTest {
@Test
void testGetUrlUsesInjectedConfig() {
// Create a mock that returns a controlled value instead of the real singleton
ConfigurationService mockConfig = Mockito.mock(ConfigurationService.class);
Mockito.when(mockConfig.getDatabaseUrl()).thenReturn("jdbc:h2:mem:testdb");
// Inject the mock through the constructor; no singleton is involved
DatabaseConnector connector = new DatabaseConnector(mockConfig);
assertEquals("jdbc:h2:mem:testdb", connector.getDatabaseUrl());
}
}
This test runs without a Spring context, without a real database, and without touching the live ConfigurationService singleton. If DatabaseConnector called ConfigurationService.getInstance() directly, this test would be impossible to write without modifying production code or using a bytecode manipulation library.
Two recent additions to the Java platform change how Singleton implementations behave at runtime: virtual threads from Project Loom and GraalVM native image.
Virtual threads share heap state with platform threads, so all seven Singleton implementations remain correct under virtual threads. In JDK 21 and 22, a virtual thread that enters a synchronized block is pinned to its carrier thread for the duration of the block, which affects throughput under contention but not correctness. JDK 24 removed this pinning behavior for most cases. Bill Pugh and enum singleton avoid the concern entirely because neither acquires a synchronized lock on the access path.
GraalVM native image initializes classes at build time by default. This means an eager or static block Singleton is constructed during the native image build rather than at first runtime access. If the constructor reads an environment variable such as System.getenv("DB_URL") or opens a socket, that call runs on the build machine where the variable does not exist and the network is not the deployment network. The Singleton captures that state permanently into the binary.
The symptom is a null field or a connection pointing to a build-time address that does not exist at runtime. GraalVM may also fail the build with an error such as:
Error: Classes that should be initialized at run time got initialized during image building
To fix this, tell GraalVM to defer class initialization to runtime using the --initialize-at-run-time flag. Pass the fully qualified class name of the Singleton:
native-image --initialize-at-run-time=com.journaldev.singleton.EagerInitializedSingleton \
-jar myapp.jar
Bill Pugh and enum singletons are unaffected when accessed only at runtime, because neither class is initialized until its first access, which happens on the deployment host after the binary has started.
| Implementation | Thread Safe | Lazy Loading | Reflection Safe | Serialization Safe | Recommended |
|---|---|---|---|---|---|
| Eager Initialization | Yes (class loading) | No | No | No (needs readResolve) |
Low-overhead resources only |
| Static Block Initialization | Yes (class loading) | No | No | No (needs readResolve) |
When constructor throws checked exception |
| Lazy Initialization | No | Yes | No | No | Single-threaded only |
| Synchronized Method | Yes | Yes | No | No | Not recommended (performance) |
| Double-Checked Locking | Yes (with volatile) |
Yes | No | No (needs readResolve) |
Acceptable; prefer Bill Pugh |
| Bill Pugh (Holder) | Yes | Yes | No | No (needs readResolve) |
Recommended when lazy loading is required |
| Enum Singleton | Yes | No | Yes | Yes | Recommended in all other cases |
Q: What is the Singleton pattern in Java and why is it used?
A: The Singleton pattern is a creational design pattern that restricts a class to exactly one instance and provides a global access point to retrieve it. It is used when a single shared resource must coordinate actions across a system, such as a logging service, application configuration manager, or database connection pool. The pattern was introduced in the Gang of Four book Design Patterns (1994) and is one of the most widely recognized patterns in Java.
Q: Which Singleton implementation is the best choice for a multithreaded Java application?
A: The Bill Pugh Singleton (initialization-on-demand holder idiom) is the recommended general-purpose implementation when lazy loading is required. It is thread-safe without explicit synchronization and requires no volatile keyword. The enum singleton is the recommended choice when lazy initialization is not required, because it is also immune to reflection and serialization attacks at the JVM level.
Q: What is double-checked locking in Java Singleton and why is volatile required?
A: Double-checked locking reduces synchronization overhead by checking whether the instance is null before and after acquiring the lock. Without the volatile keyword, the JVM or CPU may reorder the steps of object construction (memory allocation, initialization, reference assignment), allowing a second thread to read a non-null but incompletely initialized instance. Declaring the instance variable volatile enforces a happens-before relationship that prevents this reordering.
Q: How does the enum Singleton prevent reflection and serialization attacks?
A: The JVM prohibits reflective instantiation of enum types; calling Constructor.newInstance() on an enum throws IllegalArgumentException. For serialization, the JVM handles enum deserialization by returning the existing constant rather than creating a new instance, so readResolve() is not needed. These guarantees are provided at the JVM level and cannot be circumvented.
Q: What is the difference between a Java Singleton and a static class?
A: A Singleton is an object instance with encapsulated state, capable of implementing interfaces, supporting inheritance, and being passed as a dependency. A static class (a class with only static methods and fields) cannot be instantiated, cannot implement interfaces in a polymorphic context, and cannot be easily mocked in unit tests. Use Singleton when you need stateful behavior or interface-based abstraction; use a static class for stateless utility methods.
Q: Can a Singleton be broken by serialization in Java?
A: Yes. Java’s default deserialization mechanism bypasses the constructor and creates a new object, which results in a second instance and breaks the Singleton guarantee. To prevent this, implement the readResolve() method to return the existing instance. Alternatively, use enum singleton, which is immune to serialization attacks because the JVM handles enum deserialization by returning the existing constant.
Q: How do I use a Singleton pattern in a Spring application?
A: Spring beans are singleton-scoped by default within an ApplicationContext. Annotating a class with @Service, @Component, or @Repository causes Spring to create and manage exactly one instance per context. This is the preferred approach in Spring applications because the container handles lifecycle management and the bean can be injected as a constructor parameter, making it testable with mock objects.
Q: Is the Singleton pattern considered an anti-pattern?
A: The Singleton pattern is considered an anti-pattern in contexts where it introduces global mutable state, hides dependencies, or makes unit testing difficult. These problems arise most often when Singleton is called directly via getInstance() throughout the codebase rather than injected as a dependency. In modern Java applications using Spring or Guice, manual Singleton implementation is rarely necessary. The pattern is appropriate for stateless shared resources or infrastructure objects where a single coordinating instance is a genuine architectural requirement.
This article covered seven Singleton implementation variants in Java (eager, static block, lazy, synchronized method, double-checked locking, Bill Pugh, and enum), the two attack vectors that can break the Singleton guarantee (reflection and serialization) and how to prevent each, the structural comparison between Singleton and static utility classes, the role of dependency injection frameworks such as Spring as a modern alternative, and Singleton behavior under virtual threads and GraalVM native image.
You can now select the correct Singleton implementation for your use case based on whether lazy loading is required, apply volatile correctly when implementing double-checked locking, protect your Singletons against reflection and serialization attacks, and decide when to replace a manual Singleton with a Spring-managed bean.
For deeper coverage of related topics, see:
Thanks for learning with the DigitalOcean Community. Check out our offerings for compute, storage, networking, and managed databases.
Java and Python Developer for 20+ years, Open Source Enthusiast, Founder of https://www.askpython.com/, https://www.linuxfordevices.com/, and JournalDev.com (acquired by DigitalOcean). Passionate about writing technical articles and sharing knowledge with others. Love Java, Python, Unix and related technologies. Follow my X @PankajWebDev
Building future-ready infrastructure with Linux, Cloud, and DevOps. Full Stack Developer & System Administrator. Technical Writer @ DigitalOcean | GitHub Contributor | Passionate about Docker, PostgreSQL, and Open Source | Exploring NLP & AI-TensorFlow | Nailed over 50+ deployments across production environments.
owesome post…evrything is discussed about singleton.keep it up…nd thanks
- poonam
nice tutorial thanks … i have one question fro you How annotations works internally?
- Tarun Soni
Sir, As per u provide contains which one is the best practices for the Singleton Pattern. Regards Vishnu
- Vishnu
Hi Pankaj, Can we create more than one object of a singleton class using serialization ? Please provide your view in detail about in which condition Singleton classes can have more than one objects. Thanks in advance. Regards, H Singh
- H Singh
Very good site for design patterns. Explanation is easy and up to the mark. Thanks.
- Prakash
This is a nice article and almost everything is covered. Thanks a ton.
- Anshul Jain
Very nice tutorial. It help me lot to understand the singleton. Could you please help me how protected Object readResolve() method make i class a singleton.
- DHARMENDRA KUMAR SAHU
Get paid to write technical tutorials and select a tech-focused charity to receive a matching donation.
Full documentation for every DigitalOcean product.
The Wave has everything you need to know about building a business, from raising funding to marketing your product.
Stay up to date by signing up for DigitalOcean’s Infrastructure as a Newsletter.
New accounts only. By submitting your email you agree to our Privacy Policy
Scale up as you grow — whether you're running one virtual machine or ten thousand.
From GPU-powered inference and Kubernetes to managed databases and storage, get everything you need to build, scale, and deploy intelligent applications.