Ответ
В Java существует несколько способов реализации паттерна Singleton. Наиболее надежные и рекомендуемые — с использованием enum или статического внутреннего класса (Initialization-on-demand holder idiom).
1. Enum Singleton (рекомендуемый по Effective Java):
public enum Singleton {
INSTANCE;
public void doSomething() {
// реализация метода
}
}
- Плюсы: автоматическая потокобезопасность, защита от рефлексии и сериализации, лаконичный синтаксис.
- Минусы: не поддерживает ленивую инициализацию в классическом понимании (enum загружается при первом обращении).
2. Singleton через статический внутренний класс (Holder):
public class Singleton {
private Singleton() {}
private static class Holder {
static final Singleton INSTANCE = new Singleton();
}
public static Singleton getInstance() {
return Holder.INSTANCE;
}
}
- Плюсы: ленивая инициализация (экземпляр создается при первом вызове
getInstance()), потокобезопасность за счет механизмов загрузки классов JVM. - Минусы: уязвим к рефлексии (можно обойти приватный конструктор).
Почему эти способы лучше классических?
- Классический
synchronizedметод (getInstance()) создает избыточную синхронизацию после инициализации, снижая производительность. - Double-Checked Locking сложен в корректной реализации (до Java 5 был сломан из-за проблем с моделью памяти).
Вывод: для большинства случаев используйте enum, если не требуется наследование или сложная ленивая инициализация.