Java Singleton Pattern Example

๐Ÿ” Singleton Pattern in Java 8 — Step-by-Step Guide

The Singleton Pattern ensures that only one instance of a class exists in the JVM and provides a global access point to it.
It’s a classic creational design pattern used when you need exactly one shared object managing global state or resources.


๐ŸŽฏ When & Why to Use a Singleton

Use the Singleton Pattern when:

  • You want to share one object (e.g., configuration manager, cache, logger, connection pool).

  • You need to coordinate actions globally (e.g., central event dispatcher).

  • You must prevent multiple instances that could cause inconsistency or resource conflicts.

✅ Benefits

  • Guarantees a single shared instance

  • Provides controlled access via a static method

  • Saves memory by avoiding duplicate objects

  • Enables lazy initialization

  • Thread-safe options available in Java 8


⚙️ Key Principles

  1. Private constructor prevents external instantiation.

  2. Static instance variable holds the single instance.

  3. Public static method (like getInstance()) provides access.

  4. Optionally, synchronize or use static holder for thread safety.

  5. Class can be made final to prevent subclassing.


๐Ÿงฉ 1️⃣ Double-Checked Locking Singleton (Thread-Safe in Java 8)

๐Ÿ’ก Why it works

In Java 8, the volatile keyword guarantees visibility and prevents instruction reordering, making the Double-Checked Locking (DCL) approach both lazy and thread-safe.

package com.vinod.patterns; /** * Thread-safe Singleton using Double-Checked Locking. * Works correctly in Java 8 due to 'volatile' semantics. */ public final class VinodSingleton { // Volatile ensures proper visibility across threads private static volatile VinodSingleton instance; // Private constructor prevents instantiation private VinodSingleton() { System.out.println("Singleton instance created!"); } // Global access method public static VinodSingleton getInstance() { if (instance == null) { // First check (no lock) synchronized (VinodSingleton.class) { if (instance == null) { // Second check (with lock) instance = new VinodSingleton(); } } } return instance; } }

๐Ÿง  How it works (Step-by-Step)

StepActionDescription
1Class loadsNo instance created yet
2First getInstance() callChecks if instance == null
3Enters synchronized blockOnly first thread proceeds
4Creates new instanceStored in instance
5Later callsSkip synchronization (fast path)

Thread-safe, lazy initialization, and efficient after first access.


๐Ÿงฉ 2️⃣ Static Inner Class Singleton (Recommended Java 8 Approach)

๐Ÿ’ก Why use it

This approach leverages Java’s class loading mechanism — the inner class isn’t loaded until it’s referenced, making it both lazy and thread-safe without explicit synchronization.

package com.vinod.patterns; /** * Singleton using Inner Static Holder Pattern. * Lazy, thread-safe, and efficient in Java 8. */ public final class VinodHolderSingleton { // Private constructor private VinodHolderSingleton() { System.out.println("Holder-based Singleton instance created!"); } // Inner static class - loaded only when referenced private static class Holder { private static final VinodHolderSingleton INSTANCE = new VinodHolderSingleton(); } // Public access point public static VinodHolderSingleton getInstance() { return Holder.INSTANCE; } }

๐Ÿง  Step-by-Step Explanation

  1. VinodHolderSingleton class loads → inner Holder class not loaded yet.

  2. First call to getInstance() triggers loading of Holder.

  3. JVM initializes Holder.INSTANCE exactly once (thread-safe).

  4. Any future call just returns the same instance.

No synchronization overhead and 100 % thread-safe — ideal in Java 8.


๐Ÿงฉ 3️⃣ Enum Singleton (Simplest & Reflection-Safe)

๐Ÿ’ก Why use it

Since Java 5, the Enum Singleton is the most secure method. It’s serialization-safe, reflection-proof, and inherently thread-safe.

package com.vinod.patterns; /** * Simplest Singleton using Enum. * Safe against serialization and reflection. */ public enum VinodEnumSingleton { INSTANCE; public void showMessage() { System.out.println("Enum Singleton Instance Working!"); } }

Usage:

VinodEnumSingleton.INSTANCE.showMessage();

✅ Automatically prevents:

  • Multiple instances via reflection

  • Duplication via serialization


๐Ÿงช Test Program

package com.vinod.patterns; public class SingletonTest { public static void main(String[] args) { System.out.println("Testing Singleton Implementations...\n"); VinodSingleton s1 = VinodSingleton.getInstance(); VinodSingleton s2 = VinodSingleton.getInstance(); VinodHolderSingleton h1 = VinodHolderSingleton.getInstance(); VinodHolderSingleton h2 = VinodHolderSingleton.getInstance(); VinodEnumSingleton e1 = VinodEnumSingleton.INSTANCE; VinodEnumSingleton e2 = VinodEnumSingleton.INSTANCE; System.out.println("\nAre all Singletons identical?"); System.out.println("VinodSingleton: " + (s1 == s2)); System.out.println("VinodHolderSingleton: " + (h1 == h2)); System.out.println("VinodEnumSingleton: " + (e1 == e2)); } }

Sample Output

Testing Singleton Implementations... Singleton instance created! Holder-based Singleton instance created! Enum Singleton Instance Working! Are all Singletons identical? VinodSingleton: true VinodHolderSingleton: true VinodEnumSingleton: true

๐Ÿงญ Comparison Table

PatternThread-SafeLazy InitReflection-SafeSerialization-SafeRecommended?
Double-Checked Locking๐Ÿ‘ Yes
Static Holder⚠️ (use private guard)⚠️ (add readResolve)✅ Best
Enum๐Ÿš€ Ideal

๐Ÿง  Key Takeaways

  • Use Static Inner Class or Enum Singleton for Java 8 — they’re thread-safe and lazy by default.

  • Always prevent external creation via:

    • private constructor

    • final class

    • Reflection guards (optional)

  • Don’t overuse Singleton — prefer dependency injection for testable, scalable systems.

  • For multi-threaded or distributed systems, ensure proper synchronization and avoid static mutable state.


๐Ÿ’ฌ Real-World Example

Use CaseDescription
Logging UtilityOne logger used across all modules.
Configuration ReaderSingle global config object loaded once.
Cache ManagerShared cache across threads.
Connection Pool ManagerCentralized connection provider.

No comments:

Post a Comment

Model Context Protocol (MCP) — Complete Guide for Backend Engineers

  Model Context Protocol (MCP) — Complete Guide for Backend Engineers Build Tools, Resources, and AI-Driven Services Using LangChain Moder...

Featured Posts