Проанализируйте Java-код: class Singleton { private static Singleton inst; public static Singleton get() { if (inst == null) inst = new Singleton(); return inst; } } — какая проблема возникает в многопоточной среде и как можно безопасно реализовать одиночку (lazy init, synchronized, volatile, enum), с объяснением компромиссов

7 Окт в 04:12
5 +5
0
Ответы
1
Проблема. В приведённом коде при доступе из нескольких потоков возможна гонка: два потока одновременно проверяют `if (inst == null)` и оба создают новый объект — в результате может получиться >1>1>1 экземпляров. Кроме того без правильной синхронизации возможна видимость «частично сконструированного» объекта из-за переупорядочивания записей в памяти.
Способы безопасной реализации (с кратким объяснением компромиссов):
1) Простая синхронизация метода
public static synchronized Singleton get() {
if (inst == null) inst = new Singleton();
return inst;
}
- Плюсы: проста, корректна.
- Минусы: каждый вызов блокирует, возможен небольшой накладной расход при частых вызовах.
2) Инициализация при загрузке класса (eager)
private static final Singleton inst = new Singleton();
public static Singleton get() { return inst; }
- Плюсы: простота, быстрый доступ, потокобезопасно без синхронизации.
- Минусы: экземпляр создаётся сразу при загрузке класса — нет ленивой инициализации.
3) Initialization-on-demand Holder (рекомендуемый для lazy)
private static class Holder { static final Singleton INSTANCE = new Singleton(); }
public static Singleton get() { return Holder.INSTANCE; }
- Плюсы: лениво, потокобезопасно без синхронизации, низкие накладки.
- Минусы: немного менее очевиден для новичков, но обычно лучший выбор.
4) Double-checked locking с volatile
private static volatile Singleton inst;
public static Singleton get() {
if (inst == null) {
synchronized(Singleton.class) {
if (inst == null) inst = new Singleton();
}
}
return inst;
}
- Плюсы: ленивый, минимальная синхронизация (только при первом создании).
- Минусы: требует `volatile` и корректной реализации JMM (работает корректно с Java 1.51.51.5 и новее). Чуть более сложен.
5) Enum-одиночка
public enum Singleton { INSTANCE; /* методы */ }
- Плюсы: самый защищённый вариант против сериализации и отражения (reflection), прост и безопасен.
- Минусы: немного нестандартная форма для некоторых API; экземпляр создаётся при инициализации enum-класса (по сути lazy при первом доступе к классу).
Дополнительные замечания:
- Для десериализации обычного singleton (не enum) нужен `readResolve()` чтобы сохранить единственность.
- Reflection и clone могут нарушить одиночку; enum защищён лучше всего.
- В современных JVM накладные расходы на синхронизацию невелики, но Holder/enum часто лучше по сочетанию простоты и производительности.
7 Окт в 04:16
Не можешь разобраться в этой теме?
Обратись за помощью к экспертам
Гарантированные бесплатные доработки в течение 1 года
Быстрое выполнение от 2 часов
Проверка работы на плагиат
Поможем написать учебную работу
Прямой эфир