Возможно, вы создаете несколько экземпляров, но они будут собирать мусор, потому что они нигде не используются.Ни в коем случае переменная поля static _instance не изменяет свое значение более одного раза, за один раз, когда оно переходит от нуля к действительному значению.Следовательно, потребители этого кода будут видеть только один и тот же экземпляр, несмотря на то, что было создано несколько экземпляров.
Блокировка свободного программирования
Джо Даффи в своей книге под названием Параллельное программирование в Windows на самом деле анализирует тот самый паттерн, которыйвы пытаетесь использовать в главе 10 «Модели памяти и Lock Freedom», стр. 526.
Он называет этот шаблон ленивой инициализацией расслабленной ссылки:
public class LazyInitRelaxedRef<T> where T : class
{
private volatile T m_value;
private Func<T> m_factory;
public LazyInitRelaxedRef(Func<T> factory) { m_factory = factory; }
public T Value
{
get
{
if (m_value == null)
Interlocked.CompareExchange(ref m_value, m_factory(), null);
return m_value;
}
}
/// <summary>
/// An alternative version of the above Value accessor that disposes
/// of garbage if it loses the race to publish a new value. (Page 527.)
/// </summary>
public T ValueWithDisposalOfGarbage
{
get
{
if (m_value == null)
{
T obj = m_factory();
if (Interlocked.CompareExchange(ref m_value, obj, null) != null && obj is IDisposable)
((IDisposable)obj).Dispose();
}
return m_value;
}
}
}
Как мы можемПосмотрите, в приведенном выше примере методы блокируются бесплатно за счет создания одноразовых объектов.В любом случае свойство Value не изменится для потребителей такого API.
Балансировка компромиссов
Lock Freedom имеет свою цену и требует тщательного выбора компромиссов.В этом случае цена свободы блокировки заключается в том, что вы должны создавать экземпляры объектов, которые вы не собираетесь использовать.Это может быть приемлемой ценой для оплаты, поскольку вы знаете, что, будучи свободными от блокировки, снижается риск возникновения взаимоблокировок, а также конкуренции за потоки.
В этом конкретном экземпляре, однако, семантика синглтона по сути является созданием одиночного экземпляра объекта, поэтому я бы предпочел выбрать Lazy<T>
, как @Centro цитирует в своем ответе.
Тем не менее, все еще напрашивается вопрос, когда должен использовать Interlocked.CompareExchange
?Мне понравился ваш пример, он довольно провокационен, и многие люди очень быстро опровергают его как неправильный, если он не ужасно неправильный, как цитаты @Blindy.
Все сводится к тому, рассчитали ли вы компромиссы и решили:
- Насколько важно, чтобы вы создали один и только один экземпляр?
- Насколько важно быть свободным от блокировки?
Пока вы знаете о компромиссах и принимаете осознанное решение создавать новые объекты в интересах освобождения от блокировки, ваш пример также может быть приемлемым ответом.