싱글톤 패턴 (Singleton Pattern)
생성자를 여러차례 호출하여도 무조건 하나의 객체만 생성하도록 하고, 그 객체로의 전역 접근을 제공
public sealed class Singleton
{
private static Singleton? uniqueInsance = null;
/// <summary>
/// private 생성자 => Singleton 클래스 내에서만 객체 생성 가능
/// </summary>
private Singleton() { }
public static Singleton GetInstance()
{
// null인 경우에만 객체를 새로 생성
if (uniqueInsance is null)
uniqueInsance = new Singleton();
// null이 아니면 기존 객체 리턴
return uniqueInsance;
}
}
1. private 생성자
- Singleton 클래스 내에서만 객체 생성이 가능하다.
2. GetInstance()
- uniqueInstance가 null인 경우에만 Singleton 객체를 생성한다.
- uniqueInstance가 null이 아닌 경우에는 기존에 생성해놨던 객체를 반환한다.
게으른 인스턴스 생성 (Lazyinstantiation)
인스턴스가 필요한 상황이 닥치기 전까지 인스턴스를 생성하지 않는다.
(위 코드에서 GetInstance()가 처음 호출되기 전까지는 객체가 생성되지 않는다)
멀티스레딩 문제 살펴보기
두 스레드가 uniqueInstance = new Singleton(); 에 동시에 접근하게 되는 경우,
두 개의 서로 다른 객체가 생성된다.
방법1. 메소드 동기화
- 한 스레드가 메소드 사용을 끝내기 전까지 다른 스레드는 기다려야 한다.
- 객체가 할당된 이후에는 동기화할 필요가 없음에도, 메소드를 호출할 때마다 동기화되어 불필요한 오버헤드가 발생
Java
- synchronized 키워드 사용
public class Singleton
{
private static Singleton uniqueInsance;
private Singleton() { }
public static synchronized Singleton getInstance()
{
if (uniqueInsance == null)
uniqueInsance = new Singleton();
return uniqueInsance;
}
}
C#
- [MethodImpl(MethodImplOptions.Synchronized)] 어트리뷰트 사용
public sealed class Singleton
{
private static Singleton? uniqueInsance = null;
private Singleton() { }
[MethodImpl(MethodImplOptions.Synchronized)]
public static Singleton GetInstance()
{
if (uniqueInsance is null)
uniqueInsance = new Singleton();
return uniqueInsance;
}
}
방법2. 처음부터 인스턴스 생성
public sealed class Singleton
{
private static Singleton uniqueInsance = new Singleton();
private Singleton() { }
public static Singleton GetInstance()
{
return uniqueInsance;
}
}
방법3. DCL(Double-Checked Locking) 사용
- 인스턴스가 생성되어 있는지 확인한 다음, 생성되어 있지 않았을 때만 동기화
Java
- volatile, synchronized 키워드 사용
* volatile : volatile 키워드로 선언된 변수의 의미는 운영 체제, 멀티 스레드 등에 의해 프로그램에서 수정될 수 있다는 것이다
public class Singleton {
private volatile static Singleton uniqueInsance;
private Singleton() { }
public static Singleton getInstance() {
if (uniqueInsance == null) {
synchronized (Singleton.class) {
if (uniqueInsance == null) {
uniqueInsance = new Singleton();
}
}
}
return uniqueInsance;
}
}
C#
-
public sealed class Singleton
{
private static volatile Singleton? uniqueInsance = null;
private static object syncRoot = new Object(); // 동기화 블록을 얻기 위해 사용
private Singleton() { }
public static Singleton GetInstance()
{
if (uniqueInsance is null)
{
lock (syncRoot)
{
if (uniqueInsance is null)
uniqueInsance = new Singleton();
}
}
return uniqueInsance;
}
}
'디자인패턴' 카테고리의 다른 글
[디자인패턴] Chapter 07. 어댑터 패턴과 퍼사드 패턴 (0) | 2022.11.20 |
---|---|
[디자인패턴] Chapter 03. 데코레이터 패턴 (0) | 2022.10.23 |