Java 싱글톤 패턴 구현하기
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)을 고려하세요.
- 멀티스레드 환경에서는 상태 관리에 주의하세요.
Comments