출처 : 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; } } }
댓글 없음:
댓글 쓰기