Ответ
Потокобезопасность
При ленивой инициализации в многопоточной среде может создаться несколько экземпляров. Решение: synchronized, Double-Checked Locking или статическая инициализация.
Тестируемость
Singleton усложняет модульное тестирование из-за скрытых зависимостей и глобального состояния.
Жизненный цикл
Объект живет всё время работы приложения, что может приводить к утечкам памяти.
Наследование
Если Singleton не final, его можно наследовать, нарушая принцип единственности.
Пример потокобезопасной реализации:
public class Singleton {
private static volatile Singleton instance;
private Singleton() {}
public static Singleton getInstance() {
if (instance == null) {
synchronized (Singleton.class) {
if (instance == null) {
instance = new Singleton();
}
}
}
return instance;
}
}