Ответ
Singleton — это порождающий шаблон проектирования, который гарантирует, что у класса существует только один экземпляр, и предоставляет к нему глобальную точку доступа.
Ключевые характеристики:
- Приватный конструктор: Предотвращает создание экземпляра извне с помощью оператора
new. - Статическое поле: Содержит единственный экземпляр класса.
- Публичный статический метод (например,
getInstance()): Возвращает этот экземпляр, создавая его при первом вызове (ленивая инициализация).
Базовый пример (НЕ потокобезопасный):
public class SimpleSingleton {
private static SimpleSingleton instance; // Статическое поле
private SimpleSingleton() { // Приватный конструктор
// Инициализация
}
public static SimpleSingleton getInstance() {
if (instance == null) {
instance = new SimpleSingleton(); // Ленивая инициализация
}
return instance;
}
}
Потокобезопасные реализации:
1. Double-Checked Locking (для производительности):
public class ThreadSafeSingleton {
// Ключевое слово volatile гарантирует видимость изменения переменной всеми потоками
private static volatile ThreadSafeSingleton instance;
private ThreadSafeSingleton() {}
public static ThreadSafeSingleton getInstance() {
if (instance == null) { // Первая проверка (без блокировки)
synchronized (ThreadSafeSingleton.class) {
if (instance == null) { // Вторая проверка (под блокировкой)
instance = new ThreadSafeSingleton();
}
}
}
return instance;
}
}
2. Инициализация при загрузке класса (проще и безопаснее):
public class EagerSingleton {
// Экземпляр создаётся при загрузке класса JVM
private static final EagerSingleton INSTANCE = new EagerSingleton();
private EagerSingleton() {}
public static EagerSingleton getInstance() {
return INSTANCE; // Просто возвращаем готовый экземпляр
}
}
Использование: Классы-менеджеры (конфигурации, подключений к БД), логгеры, кэши, пулы потоков, где важен контроль над ресурсами.
Важно: В многопоточных средах и контейнерах (например, Spring) предпочтительнее использовать dependency injection для управления жизненным циклом «одиночных» объектов.
Ответ 18+ 🔞
А, синглтон, ёпта! Ну это ж классика, блядь, как "Муму" у Тургенева! Один на весь мир, как последний мужик в деревне, которого все соседки доят.
Смотри, суть-то проще пареной репы, но если накосячить — будет пиздец, а не паттерн. Задача — чтобы у класса был один-единственный экземпляр, и чтобы все знали, где его искать, как последнюю зажигалку на районе.
Как это работает, блядь?
- Конструктор приватный — чтобы всякие умники не лезли с
new MyClass(), как козёл на базар. Сам решаю, когда рождаться. - Поле статическое — где этот единственный экземпляр, царь и бог, будет храниться.
- Метод
getInstance()— глобальная точка доступа, типа "эй, дай-ка сюда того самого мужика!". Если его ещё нет — создаём, лениво, по первому требованию.
Вот тебе наивный, дурацкий вариант (для одного потока):
public class SimpleSingleton {
private static SimpleSingleton instance;
private SimpleSingleton() {
// Тут можешь инициализировать своё королевство
}
public static SimpleSingleton getInstance() {
if (instance == null) {
instance = new SimpleSingleton(); // Рождается по заявке
}
return instance;
}
}
Но если с двух потоков одновременно прилетит getInstance() — может родиться два близнеца, а это уже не синглтон, а пиздец. Два логгера, два коннекта к базе — всё, анархия!
Поэтому для взрослых, многопоточных проектов:
1. Double-Checked Locking (Хитрый, как жопа с ручками)
public class ThreadSafeSingleton {
private static volatile ThreadSafeSingleton instance; // volatile — чтобы не накосячила оптимизация
private ThreadSafeSingleton() {}
public static ThreadSafeSingleton getInstance() {
if (instance == null) { // Первый быстрый чек, без блокировки
synchronized (ThreadSafeSingleton.class) { // Теперь серьёзно, под замок
if (instance == null) { // Второй чек, уже под прицелом
instance = new ThreadSafeSingleton();
}
}
}
return instance;
}
}
2. Инициализация при загрузке класса (Простой и надёжный, как кирпич)
public class EagerSingleton {
// JVM создаст этот экземпляр сразу, при загрузке класса. Ленивости ноль, зато безопасно.
private static final EagerSingleton INSTANCE = new EagerSingleton();
private EagerSingleton() {}
public static EagerSingleton getInstance() {
return INSTANCE; // Просто выдаём то, что уже есть
}
}
Где это, блядь, применять? Да везде, где нужен один-единственный главный по тарелочкам: менеджер конфигурации, логгер (чтобы все в одну трубу писали), соединение с базой данных, кэш, пул потоков. Главное — не злоупотреблять, а то превратишь всё в одно большое глобальное говно, в рот меня чих-пых!
И да, в современных фреймворках вроде Spring эту хуйню часто берут на себя — они сами создают бины в единственном экземпляре. Но понимать, как это работает изнутри — must have, иначе будешь как Герасим, только "Муму" говорить.