수색…


정적으로 초기화 된 싱글 톤

public class Singleton
{
    private readonly static Singleton instance = new Singleton();
    private Singleton() { }
    public static Singleton Instance => instance;
}

이 구현 때문에이 경우에는 스레드 안전 instance 객체가 정적 생성자에서 초기화됩니다. CLR은 이미 모든 정적 생성자가 스레드로부터 안전하게 실행되도록합니다.

돌연변이 instance 는 thread 세이프 조작이 아니기 때문에, readonly 속성은 초기화 후에 불변의 것을 보증합니다.

게으른 스레드로부터 안전한 Singleton (Double Checked Locking 사용)

싱글 톤의이 스레드 안전 버전은 static 초기화가 스레드로부터 안전하다고 보장되지 않는 초기 버전의 .NET에서 필요했습니다. 프레임 워크의보다 현대적인 버전에서는 일반적으로 다음 패턴으로 구현 실수를하기 쉽기 때문에 정적으로 초기화 된 싱글 톤 이 선호됩니다.

public sealed class ThreadSafeSingleton
{
   private static volatile ThreadSafeSingleton instance;
   private static object lockObject = new Object();

   private ThreadSafeSingleton()
   {
   }

   public static ThreadSafeSingleton Instance
   {
      get 
      {
         if (instance == null) 
         {
            lock (lockObject) 
            {
               if (instance == null)
               {
                  instance = new ThreadSafeSingleton();
               }
            }
         }

         return instance;
      }
   }
}

if (instance == null) 검사는 잠금을 얻기 전에 한 번, 이후에 한 번 두 번 수행됩니다. 이 구현은, 최초의 null 체크을 실시하지 않아도 thread에 대해서 안전합니다. 그러나 이는 인스턴스가 요청 될 때마다 잠금이 획득되어 성능이 저하 될 수 있음을 의미합니다. 첫 x 째 널 (NULL) 점검이 추가되어 필요하지 않으면 잠금이 획득되지 않습니다. 두 번째 널 검사는 잠금을 획득 한 첫 번째 스레드 만 인스턴스를 작성하도록합니다. 다른 스레드는 채울 인스턴스를 찾고 건너 뜁니다.

게으른 스레드로부터 안전한 Singleton (Lazy 사용) )

.Net 4.0 유형 지연은 thread-safe 객체 초기화를 보장하므로이 유형을 사용하여 Singleton을 만들 수 있습니다.

public class LazySingleton
{
    private static readonly Lazy<LazySingleton> _instance =
        new Lazy<LazySingleton>(() => new LazySingleton());
 
    public static LazySingleton Instance
    {
        get { return _instance.Value; }
    }

    private LazySingleton() { }
}

Lazy<T> 를 사용하면 객체가 호출 코드의 어딘가에서 사용될 때만 인스턴스화됩니다.

간단한 사용법은 다음과 같습니다.

using System;
                    
public class Program
{
    public static void Main()
    {
        var instance = LazySingleton.Instance;
    }
}

.NET Fiddle에서의 라이브 데모

게으른 스레드 보안 싱글 톤 (.NET 3.5 이상, 대체 구현)

.NET 3.5 이하에서는 Lazy<T> 클래스가 없으므로 다음 패턴을 사용합니다.

public class Singleton
{
    private Singleton() // prevents public instantiation
    {
    }

    public static Singleton Instance
    {
        get
        {
            return Nested.instance;
        }
    }
    
    private class Nested
    {
        // Explicit static constructor to tell C# compiler
        // not to mark type as beforefieldinit
        static Nested()
        {
        }

        internal static readonly Singleton instance = new Singleton();
    }
}

이것은 Jon Skeet의 블로그 게시물 에서 영감을 얻었 습니다 .

Nested 클래스는 중첩되어 private이기 때문에 Singleton 인스턴스의 인스턴스 생성은 Sigleton 클래스의 다른 멤버 (예 : public readonly 속성)에 액세스하여 트리거되지 않습니다.

더 이상 필요하지 않을 때 Singleton 인스턴스 삭제

대부분의 예제는 애플리케이션이 더 이상 객체를 필요로하지 않더라도 소유 애플리케이션이 종료 될 때까지 LazySingleton 객체를 인스턴스화하고 보유하는 LazySingleton 보여줍니다. 이에 대한 해결책은 IDisposable 을 구현하고 다음과 같이 객체 인스턴스를 null로 설정하는 것입니다.

public class LazySingleton : IDisposable
{
    private static volatile Lazy<LazySingleton> _instance;
    private static volatile int _instanceCount = 0;
    private bool _alreadyDisposed = false;

public static LazySingleton Instance
{
    get
    {
        if (_instance == null)
            _instance = new Lazy<LazySingleton>(() => new LazySingleton());
        _instanceCount++;
        return _instance.Value;
    }
}

private LazySingleton() { }

// Public implementation of Dispose pattern callable by consumers.
public void Dispose()
{ 
    if (--_instanceCount == 0) // No more references to this object.
    {       
       Dispose(true);
       GC.SuppressFinalize(this);           
    }
}

// Protected implementation of Dispose pattern.
protected virtual void Dispose(bool disposing)
{
    if (_alreadyDisposed) return; 
  
    if (disposing) 
    {
        _instance = null; // Allow GC to dispose of this instance.
        // Free any other managed objects here.
    }
  
    // Free any unmanaged objects here.
    _alreadyDisposed = true;
}

위의 코드는 응용 프로그램이 종료되기 전에 인스턴스를 삭제하지만 소비자가 사용할 때마다 개체에서 Dispose() 를 호출하는 경우에만 발생합니다. 이것이 일어날 것이라는 보장이나 그것을 강요하는 방법이 없기 때문에 인스턴스가 처형 될 것이라는 보장도 없습니다. 그러나이 클래스를 내부적으로 사용하면 각 사용 후에 Dispose() 메서드를 호출하는 것이 더 쉬워집니다. 예제는 다음과 같습니다.

public class Program
{
    public static void Main()
    {
        using (var instance = LazySingleton.Instance)
        {
            // Do work with instance
        }
    }
}

이 예제는 스레드로부터 안전하지 않습니다 .



Modified text is an extract of the original Stack Overflow Documentation
아래 라이선스 CC BY-SA 3.0
와 제휴하지 않음 Stack Overflow