C# 싱글톤
이 전략에서는 클래스의 임의 구성원을 처음으로 참조할 때에 인스턴스가 만들어집니다. 공용 언어 런타임이 변수 초기화를 담당합니다. 파생을 차단하기 위해 클래스가 sealed로 표시되며 이로 인해 인스턴스가 추가될 수 있습니다. 클래스를 sealed로 표시할 때의 장단점에 대한 설명은 [Sells03]을 참조하십시오. 또한 변수가 readonly로 표시됩니다. 이 표시는 정적 초기화 (여기서 표시된 것처럼) 중이나 클래스 생성자에서만 변수를 할당할 수 있음을 의미합니다. 여기서는 정적 초기화가 나타나 있습니다.
이 구현은 공용 언어 런타임을 사용하여 변수를 초기화한다는 점을 제외하면 앞의 예제와 유사합니다. 이 구현에서는 싱글톤(Singleton) 패턴이 해결하려고 하는 두 가지 문제 즉, 글로벌 액세스와 인스턴스화 제어에 대해 다룹니다. public static 속성은 인스턴스에 글로벌 액세스 포인트를 제공합니다. 또한 생성자가 private로 선언되기 때문에 클래스 외부에서는 싱글톤(Singleton) 클래스를 인스턴스화할 수 없습니다. 따라서 변수가 의미하는 것은 시스템에 존재할 수 있는 인스턴스만을 말합니다.
싱글톤(Singleton) 인스턴스는 private로 선언된 정적 구성원 변수에 의해 참조되므로 Instance 속성 호출이 클래스를 처음으로 참조한 후에야 비로소 인스턴스화가 수행됩니다. 따라서 이 솔루션은 싱글톤(Singleton)의 Design Patterns 양식에서처럼 지연 인스턴스화 속성 양식을 구현합니다.
이 방식의 유일한 단점은 인스턴스화 구성에 대한 제어가 약간 저하된다는 점입니다. Design Patterns 양식에서는 인스턴스화 이전에 비기본 생성자를 사용하거나 다른 작업을 수행할 수 있었습니다. 이 솔루션에서는 .NET Framework가 초기화를 수행하므로 이 옵션이 필요 없습니다. 대부분의 경우는 .NET에서 싱글톤(Singleton)을 구현하기 위해 정적 초기화가 더 선호됩니다.
멀티 스레드 싱글톤(Singleton)
대부분의 상황에는 정적 초기화가 적합합니다. 응용 프로그램이 인스턴스화를 연기해야 하고, 인스턴스화 이전에 비기본 생성자를 사용하거나 다른 작업을 수행해야 하고, 멀티 스레드 환경에서 작업해야 하는 경우는 다른 솔루션이 필요합니다. 하지만 정적 초기화 예제에서처럼 스레드 안정성을 보장하기 위해 공용 언어 런타임을 사용할 수 없는 경우가 존재합니다. 이러한 경우는 여러 개의 스레드에 대해 개체 인스턴스가 하나만 만들어지도록 특정한 언어 성능을 사용해야 합니다. 보다 더 일반적인 솔루션은 각각의 스레드가 싱글톤(Singleton) 인스턴스를 동시에 만들지 못하도록 막기 위해 이중 확인 잠금(Double-Check Locking)[Lea99] 관용구를 사용하는 것입니다.
참고:공용 언어 런타임은 다른 환경에서 흔히 나타나는 이중 확인 잠금(Double-Check Locking) 사용에 관련된 문제를 해결합니다. 이 문제에 대한 자세한 내용은 메릴랜드 주립대, 컴퓨터 사이언스 학과 웹 사이트(http://www.cs.umd.edu/~pugh/java/memoryModel/DoubleCheckedLocking.html)에서 "The 'Double-Checked Locking Is Broken' Declaration" 을 참조하십시오.
다음 구현에서는 싱글톤(Singleton)의 인스턴스가 아직 만들어지지 않았을 때 한 개의 스레드만이 임계 영역(lock 블록에 의해 식별)에 들어갈 수 있습니다.
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; } } }
이 방식에서는 인스턴스가 필요할 경우에만 인스턴스가 단 한 개만 만들어지도록 합니다. 또한 인스턴스 변수에 액세스할 수 있기 전에 인스턴스 변수 할당을 완료하도록 변수를 volatile로 선언합니다. 마지막으로 이 방식에서는 교착 상태를 방지하기 위해 유형 자체를 잠그지 않고 syncRoot 인스턴스를 사용하여 잠급니다.
이 이중 확인 잠금(double-check locking) 방식은 Instance 속성 메서드의 모든 호출에 대한 독점적인 잠금을 막으면서도 스레드 동시 발생의 문제를 해결합니다. 이 방식에서는 또한 개체가 처음으로 액세스될 때까지는 인스턴스화를 연기할 수 있습니다. 실제로 응용 프로그램에는 이러한 유형의 구현이 거의 필요 없습니다. 대부분의 경우는 정적 초기화 방식만으로 충분합니다.
결과
C#에서 싱글톤(Singleton)을 구현할 경우 다음과 같은 이점과 단점이 있습니다.
이점
.NET Framework에서는 정적 변수 초기화가 언제 어떻게 일어나는지를 명시적으로 정의하므로 정적 초기화 방식이 가능합니다.
위의 "멀티 스레드 싱글톤(Singleton)"에서 이미 설명한 이중 확인 잠금(Double-Check Locking) 관용구가 공용 언어 런타임에서 올바로 구현됩니다.
단점
멀티 스레드 응용 프로그램에 명시적 초기화가 필요한 경우는 스레딩 문제를 예방하기 위해 미리 조치를 취해야 합니다.
참고 자료
[Gamma95] Gamma, Helm, Johnson 및 Vlissides. Design Patterns: Elements of Reusable Object-Oriented Software. Addison-Wesley, 1995.
[Lea99] Lea, Doug. Concurrent Programming in Java, Second Edition. Addison-Wesley, 1999.
[Sells03] Sells, Chris. "Sealed Sucks." sellsbrothers.com News. 다음 웹 사이트에서 구할 수 있습니다: http://www.sellsbrothers.com/news/showTopic.aspx?ixTopic=411
참고: 제목과는 무관하게 "Sealed Sucks" 기사는 클래스를 sealed로 표시할 때의 장단점에 대해 실제로 설명합니다
'Programming > C#' 카테고리의 다른 글
C#에서의 '마우스 클릭(mousedown) 상태'에서 '마우스 이벤트' 일어나지 않는 문제 (0) | 2010.07.06 |
---|---|
Windows Forms FAQ - Windows Forms (0) | 2010.07.02 |
Singleton (0) | 2010.07.02 |
창크기 조절 막기 (0) | 2010.07.02 |
파일 드래그&드롭 (1) | 2010.06.30 |