Full Stack • Java • System Design • Cloud • AI Engineering

Singleton Design Pattern in Java

Learn Singleton Design Pattern in Java with purpose, real-time examples, framework examples, diagrams, code, input/output, benefits, limitations, and interview questions.

Introduction

Singleton is one of the most commonly used Creational Design Patterns in Java.

It ensures that a class has only one object instance in the entire application and provides a global access point to that instance.


Purpose of Singleton Pattern

The main purpose of Singleton is:

Create only one object and reuse it everywhere.

Singleton is useful when one shared object is enough for the complete application.


Real-Time Analogy

Think about a company CEO.

A company may have many employees, departments, and managers.

But usually there is only one CEO.

Everyone refers to the same CEO.

Company → One CEO
Application → One Singleton Object

Singleton Pattern Diagram

flowchart TD

A[Application Code]

A --> B[getInstance Method]

B --> C{Instance Already Created?}

C -->|Yes| D[Return Existing Object]

C -->|No| E[Create New Object]

E --> F[Store Static Instance]

F --> D

Where Singleton is Used?

Singleton is commonly used for:

  • Logger
  • Configuration Manager
  • Cache Manager
  • Database Connection Manager
  • Thread Pool Manager
  • Application Context
  • Object Registry

Basic Singleton Structure

classDiagram

class Singleton {
  - static Singleton instance
  - Singleton()
  + static getInstance() Singleton
}

Key Rules

A Singleton class should have:

  1. Private constructor
  2. Static instance variable
  3. Public static method to return instance

Simple Singleton Example

public class AppConfig {

    private static AppConfig instance;

    private AppConfig() {
        System.out.println("AppConfig object created");
    }

    public static AppConfig getInstance() {
        if (instance == null) {
            instance = new AppConfig();
        }
        return instance;
    }

    public void showConfig() {
        System.out.println("Application configuration loaded");
    }
}

Main Class

public class SingletonDemo {

    public static void main(String[] args) {

        AppConfig config1 = AppConfig.getInstance();
        AppConfig config2 = AppConfig.getInstance();

        config1.showConfig();

        System.out.println(config1 == config2);
    }
}

Output

AppConfig object created
Application configuration loaded
true

Output Explanation

The message:

AppConfig object created

prints only once.

Even though we called:

AppConfig.getInstance();

two times, only one object was created.

The result:

true

means both references point to the same object.


Object Flow

sequenceDiagram

participant Main
participant AppConfig

Main->>AppConfig: getInstance()
AppConfig-->>Main: Create and return object

Main->>AppConfig: getInstance()
AppConfig-->>Main: Return existing object

Problem With Basic Singleton

The above implementation is not thread-safe.

In a multi-threaded application, two threads may create two objects at the same time.


Thread Safety Problem

flowchart TD

A[Thread 1 calls getInstance]

B[Thread 2 calls getInstance]

A --> C[instance is null]

B --> D[instance is null]

C --> E[Create Object 1]

D --> F[Create Object 2]

This breaks the Singleton rule.


Thread-Safe Singleton

public class ThreadSafeAppConfig {

    private static ThreadSafeAppConfig instance;

    private ThreadSafeAppConfig() {
        System.out.println("ThreadSafeAppConfig object created");
    }

    public static synchronized ThreadSafeAppConfig getInstance() {
        if (instance == null) {
            instance = new ThreadSafeAppConfig();
        }
        return instance;
    }
}

Problem With synchronized Method

The synchronized method is thread-safe but may reduce performance.

Every call locks the method, even after the object is already created.


Double Checked Locking Singleton

public class DatabaseConnectionManager {

    private static volatile DatabaseConnectionManager instance;

    private DatabaseConnectionManager() {
        System.out.println("DatabaseConnectionManager object created");
    }

    public static DatabaseConnectionManager getInstance() {

        if (instance == null) {
            synchronized (DatabaseConnectionManager.class) {
                if (instance == null) {
                    instance = new DatabaseConnectionManager();
                }
            }
        }

        return instance;
    }

    public void connect() {
        System.out.println("Database connected successfully");
    }
}

Main Class

public class DatabaseDemo {

    public static void main(String[] args) {

        DatabaseConnectionManager db1 =
                DatabaseConnectionManager.getInstance();

        DatabaseConnectionManager db2 =
                DatabaseConnectionManager.getInstance();

        db1.connect();

        System.out.println(db1 == db2);
    }
}

Output

DatabaseConnectionManager object created
Database connected successfully
true

Why volatile is Used?

private static volatile DatabaseConnectionManager instance;

volatile ensures that all threads see the latest value of the instance variable.

It prevents visibility issues in multi-threaded environments.


Best Singleton Approach in Java

Enum Singleton is considered one of the safest Singleton implementations.

public enum LoggerService {

    INSTANCE;

    public void log(String message) {
        System.out.println("LOG: " + message);
    }
}

Main Class

public class EnumSingletonDemo {

    public static void main(String[] args) {

        LoggerService logger1 = LoggerService.INSTANCE;
        LoggerService logger2 = LoggerService.INSTANCE;

        logger1.log("Application started");

        System.out.println(logger1 == logger2);
    }
}

Output

LOG: Application started
true

Why Enum Singleton is Better?

Enum Singleton protects against:

  • Reflection issues
  • Serialization issues
  • Multiple object creation
  • Thread safety problems

Real-Time Example: Logger

In enterprise applications, we usually need one common logger.

public class ApplicationLogger {

    private static final ApplicationLogger INSTANCE = new ApplicationLogger();

    private ApplicationLogger() {
    }

    public static ApplicationLogger getInstance() {
        return INSTANCE;
    }

    public void info(String message) {
        System.out.println("[INFO] " + message);
    }

    public void error(String message) {
        System.out.println("[ERROR] " + message);
    }
}

Logger Usage

public class OrderService {

    public void createOrder() {
        ApplicationLogger logger = ApplicationLogger.getInstance();
        logger.info("Order created successfully");
    }
}

Output

[INFO] Order created successfully

Framework Examples

Spring Framework

By default, Spring Beans are Singleton scoped.

@Service
public class PaymentService {

    public void processPayment() {
        System.out.println("Payment processed");
    }
}

Spring creates only one instance of PaymentService by default.


Spring Singleton Scope

flowchart LR

A[Spring Container]

A --> B[PaymentService Bean]

C[Controller 1] --> B

D[Controller 2] --> B

E[Controller 3] --> B

All controllers reuse the same Spring Bean instance.


Spring Example

@RestController
public class PaymentController {

    private final PaymentService paymentService;

    public PaymentController(PaymentService paymentService) {
        this.paymentService = paymentService;
    }

    @GetMapping("/pay")
    public String pay() {
        paymentService.processPayment();
        return "Payment Success";
    }
}

Important Spring Note

Spring Singleton is not exactly the same as GoF Singleton.

GoF Singleton:

One object per JVM classloader

Spring Singleton:

One bean per Spring ApplicationContext

Java Framework Examples

Framework Singleton Usage
Spring Default Bean Scope
Hibernate SessionFactory
Log4j Logger Instance
Runtime Runtime.getRuntime()
Cache Managers Shared Cache Object

Java Runtime Singleton Example

Runtime runtime = Runtime.getRuntime();

Runtime provides access to JVM runtime environment using Singleton-style access.


Singleton in Microservices

In microservices, Singleton can be used inside one service instance for:

  • Config cache
  • In-memory lookup data
  • Metrics registry
  • Local object registry

But remember:

Singleton is per JVM, not across multiple pods or servers.

Kubernetes Example

If one microservice has 3 pods:

Order Service Pod 1 → Singleton Object 1
Order Service Pod 2 → Singleton Object 2
Order Service Pod 3 → Singleton Object 3

Singleton does not mean one object across the entire distributed system.


Microservices Diagram

flowchart TD

A[Load Balancer]

A --> B[Order Service Pod 1<br/>Singleton Instance]

A --> C[Order Service Pod 2<br/>Singleton Instance]

A --> D[Order Service Pod 3<br/>Singleton Instance]

Benefits

  • Controls object creation
  • Saves memory
  • Provides global access
  • Useful for shared resources
  • Simple to implement
  • Good for configuration and logging

Limitations

  • Can make unit testing harder
  • Can introduce global state
  • Not ideal for distributed systems
  • Can hide dependencies
  • Thread safety must be handled carefully

When to Use Singleton

Use Singleton when:

  • Only one instance is needed
  • Object creation is expensive
  • Shared access is required
  • The object is stateless or safely manages state

Examples:

  • Logger
  • Configuration Manager
  • Cache Manager

When Not to Use Singleton

Avoid Singleton when:

  • Object holds user-specific state
  • Application needs multiple instances
  • It makes testing difficult
  • You are trying to share data across microservices

Interview Questions

What is Singleton Pattern?

Singleton ensures that only one instance of a class is created and provides global access to it.


Why is constructor private?

To prevent object creation using new.


Is Singleton thread-safe?

Basic Singleton is not thread-safe.

Use synchronized, double-checked locking, or enum Singleton.


What is the best Singleton implementation in Java?

Enum Singleton is considered safest.


Is Spring Bean Singleton same as GoF Singleton?

No.

Spring Singleton means one bean per Spring ApplicationContext.

GoF Singleton means one instance per JVM classloader.


Key Takeaways

  • Singleton is a Creational Design Pattern.
  • It restricts object creation to one instance.
  • Private constructor prevents external object creation.
  • getInstance() provides global access.
  • Enum Singleton is safest in Java.
  • Spring Beans are singleton by default.
  • In microservices, Singleton is per service instance, not global across pods.