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