Java 싱글톤 패턴 구현하기
싱글톤 패턴은 클래스의 인스턴스가 하나만 존재하도록 보장하는 디자인 패턴입니다.
Static 초기화 블록을 이용한 구현
클래스 로딩 시점에 인스턴스를 생성하는 방법입니다.
public class PhotoManager {
private static final PhotoManager sInstance;
private static final TimeUnit KEEP_ALIVE_TIME_UNIT;
static {
// 상수 초기화
KEEP_ALIVE_TIME_UNIT = TimeUnit.SECONDS;
// 싱글톤 인스턴스 생성
sInstance = new PhotoManager();
}
// private 생성자
private PhotoManager() {
// 초기화 로직
}
public static PhotoManager getInstance() {
return sInstance;
}
}
다양한 싱글톤 구현 방법
1. Eager Initialization (즉시 초기화)
public class Singleton {
private static final Singleton INSTANCE = new Singleton();
private Singleton() {}
public static Singleton getInstance() {
return INSTANCE;
}
}
장점: 간단하고 스레드 안전
단점: 사용하지 않아도 인스턴스 생성됨
2. Lazy Initialization with synchronized
public class Singleton {
private static Singleton instance;
private Singleton() {}
public static synchronized Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
장점: 필요할 때만 생성
단점: 매번 동기화 오버헤드
3. Double-Checked Locking
public class Singleton {
private static volatile Singleton instance;
private Singleton() {}
public static Singleton getInstance() {
if (instance == null) {
synchronized (Singleton.class) {
if (instance == null) {
instance = new Singleton();
}
}
}
return instance;
}
}
장점: Lazy + 효율적인 동기화
주의: volatile 키워드 필수 (Java 5+)
4. Initialization-on-demand Holder (권장)
public class Singleton {
private Singleton() {}
private static class Holder {
private static final Singleton INSTANCE = new Singleton();
}
public static Singleton getInstance() {
return Holder.INSTANCE;
}
}
장점:
- Lazy initialization
- 스레드 안전 (클래스 로딩 메커니즘 활용)
- 동기화 오버헤드 없음
5. Enum Singleton (Effective Java 권장)
public enum Singleton {
INSTANCE;
public void doSomething() {
// 메서드 구현
}
}
장점:
- 직렬화 안전
- 리플렉션 공격 방어
- 가장 간결함
사용:
Singleton.INSTANCE.doSomething();
구현 방법 비교
| 방법 | Lazy | 스레드 안전 | 직렬화 안전 | 복잡도 |
|---|---|---|---|---|
| Eager | X | O | X | 낮음 |
| Synchronized | O | O | X | 낮음 |
| Double-Checked | O | O | X | 중간 |
| Holder | O | O | X | 낮음 |
| Enum | X | O | O | 낮음 |
직렬화 문제 해결
Enum 외의 방법에서 직렬화 시 새 인스턴스가 생성되는 것을 방지:
public class Singleton implements Serializable {
private static final long serialVersionUID = 1L;
private static final Singleton INSTANCE = new Singleton();
private Singleton() {}
public static Singleton getInstance() {
return INSTANCE;
}
// 역직렬화 시 기존 인스턴스 반환
protected Object readResolve() {
return INSTANCE;
}
}
권장사항
- 대부분의 경우: Holder 패턴 사용
- 직렬화가 필요한 경우: Enum 싱글톤 사용
- Spring 환경: 스프링 빈으로 관리 (기본이 싱글톤 스코프)
주의사항
- 싱글톤은 전역 상태를 만들어 테스트를 어렵게 할 수 있습니다.
- 가능하면 의존성 주입(DI)을 고려하세요.
- 멀티스레드 환경에서는 상태 관리에 주의하세요.
Originally published at https://dss99911.github.io
Top comments (0)