출처 : Implementing Singleton in C#
using System;
public class Singleton
{
   private static Singleton instance;
   private Singleton() {}
   public static Singleton Instance
   {
      get 
      {
         if (instance == null)
         {
            instance = new Singleton();
         }
         return instance;
      }
   }
}
위와같은 Singleton 의 구현은 2가지 이득이 있다.
- instance 가 Instance property 내부에서 만들어지기 때문에 그 안에서 원하는 작업을 추가할 수 있다.
 - object 가 instance 를 사용요청을 하기 전까지는 안 만들어진다.(lazy instantiation)
 
그런데 이 녀석은 multithreaded programming 에서 안전하지 않다. instance 가 null 인지 비교하는 경우에 race condition 이 발생해서 여러 개의 singleton 을 만들어 버릴 수 있다.
Static Initialization
c++ 스펙에서는 static variable 의 초기화 순서에 대한 모호함이 있어서 원래 design pattern 에서는 static intialization 을 잘 안 쓴다.
근데 .NET Framework 에서는 변수 초기화의 처리를 통해 이 모호함(ambiguity) 를 해결했다.
public sealed class Singleton
{
   private static readonly Singleton instance = new Singleton();
   
   private Singleton(){}
   public static Singleton Instance
   {
      get 
      {
         return instance; 
      }
   }
}
 
이 코드에서는 class 에 있는 member 중 하나가 referenced 되면, instance 가 만들어지게 된다.
CLR 이 variable initialization 을 관리한다.
상속이 instance 를 추가할 수도 있어서, 상속을 막기 위해 sealed keyword 를 사용하였다.
varable 은 readonly 로 했다. readonly 은 초기화를 한 번만 할 수 있기 때문에 오직 static initialization 하는 동안에만 assign 된다.
하지만 여전히 singleton 의 기본적인 문제인 global access 와 instantiation contorl 은 가지고 있다.
이 경우에 문제는 CLR 이 intialization 을 하고 있어서 원하는 대로 초기화를 할 수 없다.
.NET 에서 가장 선호되는 방식이다.
Multithreaded
Multithreaded 에서는 아래 처럼 다른 방법을 써야한다.
using System;
public sealed class Singleton
{
   private static volatile Singleton instance;
   private static object syncRoot = new Object();
   private Singleton() {}
   public static Singleton Instance
   {
      get 
      {
         if (instance == null) 
         {
            lock (syncRoot) 
            {
               if (instance == null) 
                  instance = new Singleton();
            }
         }
         return instance;
      }
   }
}
댓글 없음:
댓글 쓰기