</>

Technology

Core Java

Difficulty

Advanced

Interview Question

What is the Singleton design pattern in Java? Implement it thread-safely.

Answer

Singleton Design Pattern in Java

Singleton ensures only one instance of a class exists throughout the application and provides a global access point to it.

Basic Singleton (NOT Thread-Safe)

Java
public class DatabaseConnection {
    private static DatabaseConnection instance;

    private DatabaseConnection() {
        System.out.println("Connecting to database...");
    }

    public static DatabaseConnection getInstance() {
        if (instance == null) {
            instance = new DatabaseConnection();  // ⚠️ Not thread-safe
        }
        return instance;
    }
}

Thread-Safe Implementations

1. Synchronized Method (simple but slow)

Java
public class DatabaseConnection {
    private static DatabaseConnection instance;

    private DatabaseConnection() {}

    public static synchronized DatabaseConnection getInstance() {
        if (instance == null) {
            instance = new DatabaseConnection();
        }
        return instance;
    }
    // Problem: synchronized on every call — performance overhead
}

2. Double-Checked Locking (Best for most cases)

Java
public class DatabaseConnection {
    // volatile ensures visibility across threads
    private static volatile DatabaseConnection instance;

    private DatabaseConnection() {}

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

3. Enum Singleton (Simplest + Thread-Safe + Serialization-Safe)

Java
public enum WebDriverManager {
    INSTANCE;

    private WebDriver driver;

    public WebDriver getDriver() {
        if (driver == null) {
            driver = new ChromeDriver();
        }
        return driver;
    }

    public void quitDriver() {
        if (driver != null) {
            driver.quit();
            driver = null;
        }
    }
}

// Usage
WebDriver driver = WebDriverManager.INSTANCE.getDriver();

4. Initialization-on-Demand Holder (Lazy, Thread-Safe, No sync)

Java
public class ConfigManager {
    private final Properties properties;

    private ConfigManager() {
        properties = new Properties();
        try {
            properties.load(new FileInputStream("config.properties"));
        } catch (IOException e) {
            throw new RuntimeException("Config not found", e);
        }
    }

    // Inner class — loaded only when first accessed
    private static class Holder {
        static final ConfigManager INSTANCE = new ConfigManager();
    }

    public static ConfigManager getInstance() {
        return Holder.INSTANCE;  // thread-safe without synchronized
    }

    public String get(String key) {
        return properties.getProperty(key);
    }
}

Singleton in Automation Frameworks

Java
// WebDriver Singleton — one browser per test class
public class BrowserFactory {
    private static volatile WebDriver driver;

    private BrowserFactory() {}

    public static WebDriver getDriver() {
        if (driver == null) {
            synchronized (BrowserFactory.class) {
                if (driver == null) {
                    WebDriverManager.chromedriver().setup();
                    driver = new ChromeDriver();
                    driver.manage().window().maximize();
                }
            }
        }
        return driver;
    }

    public static void quitDriver() {
        if (driver != null) {
            driver.quit();
            driver = null;
        }
    }
}

// Any test can call
WebDriver driver = BrowserFactory.getDriver();

Breaking Singleton (and Prevention)

Java
// Reflection can break singleton:
Constructor<Singleton> c = Singleton.class.getDeclaredConstructor();
c.setAccessible(true);
Singleton s2 = c.newInstance();  // breaks singleton!

// Prevention — throw exception in constructor if instance exists
private Singleton() {
    if (instance != null) {
        throw new RuntimeException("Use getInstance()");
    }
}
// Or use Enum — reflection-proof

Follow AutomateQA

Related Topics