이 실습에서는 Singleton 패턴의 다양한 구현 방식과 멀티스레드 안전성, 그리고 현대적 대안을 직접 구현해봅니다.
실습 목표
- Singleton 패턴의 다양한 구현 방식 이해
- 멀티스레드 환경에서의 안전성 확보
- Singleton의 문제점과 현대적 대안 학습
- 의존성 주입을 통한 Singleton 대체
실습 1: 다양한 Singleton 구현
코드 템플릿
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
| // TODO 1: Eager Initialization
public class EagerSingleton {
// TODO: 클래스 로딩 시점에 인스턴스 생성
}
// TODO 2: Lazy Initialization (Thread-unsafe)
public class LazySingleton {
// TODO: 첫 번째 호출 시 인스턴스 생성
}
// TODO 3: Thread-safe Singleton
public class ThreadSafeSingleton {
// TODO: synchronized 키워드 사용
}
// TODO 4: Double-checked Locking
public class DoubleCheckedSingleton {
// TODO: volatile과 이중 체크로 최적화
}
// TODO 5: Enum Singleton
public enum EnumSingleton {
// TODO: Enum을 활용한 최적 구현
}
// TODO 6: Inner Class Holder
public class HolderSingleton {
// TODO: 내부 클래스를 활용한 지연 로딩
}
|
실습 2: 데이터베이스 연결 관리자
요구사항
- 전역적으로 하나의 DB 연결 풀만 존재
- 설정 정보 중앙 관리
- 스레드 안전성 보장
코드 템플릿
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
| public class DatabaseManager {
private static volatile DatabaseManager instance;
private final ConnectionPool connectionPool;
// TODO: 1. Double-checked locking 구현
// TODO: 2. 설정 파일에서 DB 설정 로드
// TODO: 3. 연결 풀 초기화
// TODO: 4. Connection 반환 메서드 구현
}
// TODO: 성능 테스트 코드 작성
public class SingletonPerformanceTest {
@Test
public void comparePerformance() {
// TODO: 다양한 구현 방식의 성능 비교
}
}
|
실습 3: 현대적 대안 구현
코드 템플릿
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
| // TODO 1: Spring Bean으로 Singleton 관리
@Configuration
public class SingletonConfig {
@Bean
@Scope("singleton") // 기본값이지만 명시적 표현
public DatabaseManager databaseManager() {
// TODO: Spring이 관리하는 Singleton 구현
return null;
}
}
// TODO 2: 의존성 주입을 통한 테스트 가능한 설계
@Service
public class UserService {
private final DatabaseManager databaseManager;
// TODO: 생성자 주입으로 의존성 관리
}
|
체크리스트
기본 구현
현대적 대안
추가 도전
- 성능 벤치마크: 각 구현 방식의 성능 측정
- 직렬화 문제: Serializable Singleton 구현
- 리플렉션 공격: 리플렉션 방어 메커니즘
- 클래스로더 문제: 다중 클래스로더 환경 대응
실무 적용
안티패턴 회피
- Global State 남용 방지
- 단위 테스트 어려움 해결
- 결합도 증가 문제 인식
현대적 접근
- 의존성 주입 프레임워크 활용
- 설정 외부화
- 모니터링과 로깅 강화
핵심 포인트: Singleton은 강력하지만 위험한 패턴입니다. 현대적 개발에서는 DI Container를 통한 생명주기 관리가 더 안전하고 유연한 대안입니다.