[Design Pattern] Singleton
Updated:
싱글턴 패턴은 객체 인스턴스를 한 번만 생성하는 디자인 패턴이다.
특징
단 한 개의 인스턴스만 생성해서 프로그램 어디서든 접근할 수 있게 하는 기법이다. 즉, 생성자가 몇 번이나 호출되어도 실제로 생성되는 객체는 하나 뿐이며 최초 생성 이후에 호출된 생성자는 미리 생성해둔 객체를 반환한다. 공통된 객체를 여러 개 생성해서 써야 하는 DBCP(DataBase Connection Pool)와 같은 상황에서 주로 사용된다.
Java에서 싱글턴을 구현할 때는 생성자를 private으로 선언하고, static getInstance() 메서드를 통해 최초 생성된 객체를 받아오는 방식으로 한다.
참고로 Python 모듈은 그 자체로 싱글턴이다.
장점
- 프로그램이 시작될 때 최초 한 번만 메모리를 할당하므로, 메모리 낭비를 막을 수 있다.
- 인스턴스 남발 방지
- 전역 인스턴스이기 때문에 서로 다른 클래스의 인스턴스들 간 데이터 공유에 용이하다.
- 하나의 자원을 모두가 공유해서 써야 하는 경우 유리
단점
- 동시성 문제를 잘 고려해서 설계해야 한다.
- 멀티스레드 환경에서의 동기화 처리
- 싱글턴 인스턴스를 너무 남발하면 서로 다른 클래스의 인스턴스들 간 결합도가 높아진다.
- 객체 지향 설계 원칙에 위배 → 꼭 필요한 경우가 아니면 지양하자.
예제 코드
1. Eager Initialization
이른 초기화, Thread-safe
public class Singleton {
private static Singleton instance = new Singleton();
private Singleton() {}
public static Singleton getInstance() {
return instance;
}
}
2. Lazy Initialization
게으른 초기화, Thread-safe
synchronized 키워드를 사용해서 Thread-safe하게 만든다. 그런데 이 키워드를 사용하면 성능이 심하게 떨어져, 권장하지 않는다.
public class Singleton {
private static Singleton instance;
private Singleton() {}
public static synchronized Singleton getInstance() {
if(instance == null) {
instance = new Singleton();
}
return instance;
}
}
3. Lazy Initialization + Double-checked Locking
DCL, Thread-safe
위의 synchronized 키워드를 쓴 동기화 방식을 개선한 방식이다. 멀티스레드 환경에서도 인스턴스가 한 번만 생성된다.
public class Singleton {
private volatile static Singleton instance;
private Singleton() {}
public static Singleton getInstance() {
if(instance == null) {
synchronized(Singleton.class) {
if(instance == null) {
instance = new Singleton();
}
}
}
return instance;
}
}
4. Lazy Initialization + Lazy Holder
게으른 초기화, Holder에 의한 초기화, Thread-safe
클래스 안에 Holder 클래스를 두는 방식이다. 동시성 문제에 있어 가장 성능이 뛰어나, 제일 많이 사용된다.
public class Singleton {
private Singleton() {}
private static class LazyHolder {
public static final Singleton INSTANCE = new Singleton();
}
public static Singleton getInstance() {
return LazyHolder.INSTANCE;
}
}
참고. 싱글턴 패턴, 싱글톤 패턴을 쓰는 이유와 문제점, 싱글톤 패턴
Leave a comment