Использование Singleton в Многопоточных Сценариях. Окончание
Начало
3. Блокировка с двойной проверкой
Первая проверка: первая проверка на null. Если экземпляр не пуст, он возвращается. Эта проверка позволяет избежать накладных расходов на блокировку в большинстве вызовов после инициализации экземпляра.
Блокировка: если экземпляр null, получается блокировка.
Вторая проверка: внутри блокировки выполняется вторая проверка, т.к. другой поток мог инициализировать экземпляр между первой проверкой и получением блокировки. Если экземпляр всё ещё null после второй проверки, он создаётся.
public sealed class Singleton
{
private static Singleton instance = null;
private static readonly object lck = new object();
Singleton() {}
public static Singleton Instance
{
get
{
if (instance == null)
{
lock (lck)
{
if (instance == null)
instance = new Singleton();
}
}
}
return instance;
}
}
Это лучшее решение? Не совсем. Решение сложное и может вызвать проблемы, если его неправильно использовать.
4. Singleton с Lazy
Ленивая инициализация: класс Lazy автоматически обрабатывает ленивую инициализацию экземпляра Singleton. Экземпляр не создаётся, пока он действительно не понадобится. Lazy гарантирует, что экземпляр создаётся потокобезопасным способом, поэтому не нужно использовать блокировки или дважды проверять блокировку. Кроме того, код проще и удобнее для обслуживания, поскольку сложность синхронизации потоков инкапсулирована в классе Lazy.
public class Singleton
{
private static readonly Lazy<Singleton>
instance = new Lazy<Singleton>(
() => new Singleton());
private Singleton() {}
public static Singleton Instance
=> instance.Value;
}
Ключевые преимущества использования Lazy для реализации Singleton:
• Потокобезопасность: Lazy обрабатывает все сложности потокобезопасности, снижая риск ошибок.
• Производительность: как правило, более эффективно, так как не требует явной блокировки (которая может быть затратной).
• Простота: код намного чище и понятнее, что повышает удобство обслуживания.
Итого
Существует несколько других способов реализации этого шаблона. Lazy хорош с точки зрения производительности и ленивой работы, а также легко читаем. Это может быть хорошим стартом для начинающих изучать шаблон Singleton. Определённо стоит избегать первого способа, потому что он не потокобезопасен и может вызвать серьёзные проблемы в коде.
Источник: https://thecodeman.net/posts/how-to-use-singleton-in-multithreading