AI Skill Report Card
Generated Skill
Implementing Singleton Patterns in Java
Quick Start
Java// Enum Singleton (Recommended) public enum ConfigSingleton { INSTANCE; private String config = "default"; public void setConfig(String config) { this.config = config; } public String getConfig() { return config; } } // Usage ConfigSingleton.INSTANCE.setConfig("production");
Recommendation▾
Consider adding more specific examples
Workflow
Progress:
- Choose implementation approach (enum vs class-based)
- Implement singleton with private constructor
- Add static factory method
- Ensure thread safety
- Test single instance guarantee
- Validate serialization behavior
1. Enum Singleton (Thread-Safe by Default)
Javapublic enum DatabaseConnection { INSTANCE("jdbc:mysql://localhost:3306/db"); private final String url; private Connection connection; private DatabaseConnection(String url) { this.url = url; } public Connection getConnection() { if (connection == null) { // Initialize connection } return connection; } }
2. Class-Based Singleton (Thread-Safe)
Javapublic final class Logger { private static volatile Logger INSTANCE; private final String logLevel; private Logger() { this.logLevel = "INFO"; } public static Logger getInstance() { if (INSTANCE == null) { synchronized (Logger.class) { if (INSTANCE == null) { INSTANCE = new Logger(); } } } return INSTANCE; } }
3. Eager Initialization (Simple)
Javapublic final class AppConfig { private static final AppConfig INSTANCE = new AppConfig(); private AppConfig() {} public static AppConfig getInstance() { return INSTANCE; } }
Recommendation▾
Include edge cases
Examples
Example 1: Configuration Manager Input: Need global access to application settings
Javapublic enum ConfigManager { INSTANCE; private Properties props = new Properties(); public void setProperty(String key, String value) { props.setProperty(key, value); } public String getProperty(String key) { return props.getProperty(key); } } // Usage ConfigManager.INSTANCE.setProperty("db.host", "localhost"); String host = ConfigManager.INSTANCE.getProperty("db.host");
Example 2: Cache Manager Input: Single cache instance across application
Javapublic final class CacheManager { private static volatile CacheManager instance; private final Map<String, Object> cache = new ConcurrentHashMap<>(); private CacheManager() {} public static CacheManager getInstance() { if (instance == null) { synchronized (CacheManager.class) { if (instance == null) { instance = new CacheManager(); } } } return instance; } public void put(String key, Object value) { cache.put(key, value); } public Object get(String key) { return cache.get(key); } }
Best Practices
- Prefer enum singletons - Thread-safe, serialization-safe, prevents multiple instances
- Use double-checked locking for class-based singletons with volatile keyword
- Make constructor private to prevent external instantiation
- Consider lazy vs eager initialization based on resource cost
- Make class final to prevent subclassing
- Use dependency injection instead of singletons when possible for testability
Common Pitfalls
- Non-thread-safe implementations - Basic lazy initialization without synchronization
Java// DON'T DO THIS public static Singleton getInstance() { if (instance == null) { // Race condition! instance = new Singleton(); } return instance; }
- Overusing singletons - Creates hidden dependencies and testing difficulties
- Forgetting serialization - Class-based singletons can break during deserialization
- Performance issues - Synchronized methods on every call instead of double-checked locking
- Multiple class loaders - Different class loaders create separate instances
- Reflection attacks - Private constructors can be accessed via reflection