Java.Core.SingletonePattern

🌐 What is the Singleton Pattern?

Singleton is a creational design pattern that ensures:

  1. Only one instance of a class can exist.
  2. That instance is accessible globally.

💡 Why use Singleton?

✅ To control shared access to resources (like configuration, logging, database connection).
✅ To enforce a single point of control.
✅ Saves memory in cases where only one instance is required.


🔗 Key Properties of Singleton

PropertyMeaning
Single InstanceOnly one object of the class exists.
Global AccessThe instance is accessible via a global/static method.
Lazy or Eager InitializationInstance can be created on-demand (lazy) or at class loading time (eager).

📜 Example — Basic Singleton (Eager Initialization)

public class Logger {
    private static final Logger INSTANCE = new Logger();

    private Logger() {}  // private constructor prevents external instantiation

    public static Logger getInstance() {
        return INSTANCE;
    }

    public void log(String message) {
        System.out.println(message);
    }
}
Logger logger = Logger.getInstance();
logger.log("Application started");

📦 Lazy Initialization Singleton (On Demand)

public class DatabaseConnection {
    private static DatabaseConnection instance;

    private DatabaseConnection() {}

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

⚠️ This is not thread-safe — two threads could both see null and create two instances.


🔒 Thread-Safe Singleton (Double-Checked Locking)





public class ConfigManager {
    private static volatile ConfigManager instance;

    private ConfigManager() {}

    public static ConfigManager getInstance() {
        if (instance == null) {                      // First check (no locking)
            synchronized (ConfigManager.class) {
                if (instance == null) {              // Second check (inside lock)
                    instance = new ConfigManager();
                }
            }
        }
        return instance;
    }
}

volatile ensures visibility across threads.
✅ Double-checked locking minimizes synchronization overhead.

🚀 Best Practice — Bill Pugh Singleton (Inner Static Helper Class)





public class AppConfig {
    private AppConfig() {}

    private static class Holder {
        private static final AppConfig INSTANCE = new AppConfig();
    }

    public static AppConfig getInstance() {
        return Holder.INSTANCE;
    }
}

✅ This is the cleanest, most recommended approach.
✅ Thread-safe without synchronization cost.
✅ Relies on JVM’s classloader to guarantee safe lazy loading.

🔥 Summary Table

ApproachProsCons
Eager InitializationSimple, thread-safeInstance always created (even if not used)
Lazy InitializationOnly created when neededNot thread-safe (unless synchronized)
Double-Checked LockingThread-safe, efficientSlightly complex
Bill Pugh SingletonBest of both worlds (lazy + efficient + safe)None really (preferred method)

⚠️ Singleton in a Multithreaded Environment

  • Be careful when using Singleton in multi-threaded apps — race conditions during creation can lead to multiple instances.
  • Modern Bill Pugh approach avoids these problems.

💡 Common Singleton Use Cases

✅ Logging (Logger)
✅ Configuration (ConfigManager)
✅ Caches
✅ Database Connection Pools
✅ Service Locators


🛑 Singleton Anti-pattern Warning

  • Overusing Singleton can lead to global state, which makes testing harder.
  • In some cases, Dependency Injection is preferred over Singleton.

📚 Final Tip for Interviews

✅ Explain all approaches — Eager, Lazy, Double-Checked, Bill Pugh.
✅ Mention thread-safety challenges in multi-threaded code.
✅ Mention why overusing Singleton can hurt testability (global state).
✅ If asked best way in modern Java? — Say Bill Pugh (Static Holder Idiom).

This entry was posted in Без рубрики. Bookmark the permalink.