mojo's Blog
Singleton Pattern 본문
Singleton Pattern
목적: 시스템 내에서 클래스 객체가 하나만 허용되도록 함
사용시기
- 클래스의 객체가 정확히 하나 필요함
- 단일 객체에 대한 제어된 접근이 필요함
※ One of a Kind Objects
오직 하나의 객체로 관리되어야 할 것들
- Window Manager
- Thread Pool Manager
- Caches
- Logging
하나의 객체 관리가 왜 어려울까?
- Multi-threading 문제
- 글로벌 변수를 생각해보기
※ The Skeleton of Singleton
public class Singleton {
private static Singleton uniqueInstance;
// other useful instance variables
private Singleton() {}
public static Singleton getInstance() {
if (uniqueInstance == null) {
uniqueInstance = new Singleton();
}
return uniqueInstance;
}
// other useful methods
}
1. 생성자는 private 로 선언한다.
외부에서 객체 생성 금지
2. getInstance() 메서드를 제공한다.
static => 컴파일 타임에 Singleton 객체를 생성하여 uniqueInstance 할당
public => 외부에서 단일 객체를 불러오기 위함
※ Using Singleton on Multi-threads
두 개의 스레드가 있는 상태에서 getInstance() 메서드를 호출한다고 가정한다.
각 스레드 별로 getInstance() 메서드에 들어왔고, uniqueInstance 가 둘 다 null 인 경우
Singleton 객체를 각 스레드 별로 생성하게 된다.
그리고 서로 다른 Singleton 객체를 리턴함으로써 의도하지 않은 객체를 사용하게 된다.
※ Solving the Problem
public class Singleton {
private static Singleton uniqueInstance;
// other useful instance variables
private Singleton() {}
public static synchronized Singleton getInstance() {
if (uniqueInstance== null) {
uniqueInstance = new Singleton();
}
return uniqueInstance;
}
// other useful methods
}
첫번째 방식은 synchronized 키워드를 붙여서 스레드 하나만 접근 가능하도록 한다.
작동이 보장되는 간단한 기술이지만, 잦은 잠금으로 인해 런타임 성능에 작은 영향을 미칠 수 있다.
public class Singleton {
private static Singleton uniqueInstance = new Singleton();
// other useful instance variables
private Singleton() {}
public static Singleton getInstance() {
return uniqueInstance;
}
// other useful methods
}
두번째 방식은 컴파일 타임때 uniqueInstance 에 Singleton 객체를 할당한다.
항상 클래스를 객체화할 경우 정적으로 객체를 초기화하면 문제가 발생하지 않는다.
public class Singleton {
private volatile static Singleton uniqueInstance = null;
// other useful instance variables
private Singleton() {}
public static Singleton getInstance() {
if (uniqueInstance == null) {
synchronized(Singleton.class) {
if (uniqueInstance == null)
uniqueInstance = new Singleton();
}
}
return uniqueInstance;
}
// other useful methods
}
세번째 방식은 uniqueInstance가 null인 경우 synchronized를 안에 걸어줌으로써 한번 더 null을 체크한다.
그리고 uniqueInstance 에 volatile 키워드를 붙인다.
완벽한 솔루션이지만, 성능 문제가 없을 경우에는 두 번 확인한 잠금이 overkill 될 수 있다.
또한 최소한 Java 5를 실행하고 있는지 확인해야 한다.
* volatile: 모든 스레드가 항상 같은 공유 변수의 값을 읽어올 수 있도록 보장
메인 메모리에 해당 객체 값이 갱신되고 이로써 다른 모든 스레드들은 null 이 아닌 공유 변수에 할당된
객체를 메인 메모리로부터 바로 읽어올 수 있게 됨
'Design Patterns' 카테고리의 다른 글
Adapter Pattern (0) | 2024.06.09 |
---|---|
Decorator Pattern (0) | 2024.06.09 |
Builder Pattern (0) | 2024.06.09 |
Factory Method Pattern & Abstract Factory Pattern (0) | 2024.06.09 |
Mediator Pattern (0) | 2024.06.06 |