싱글턴으로 만든 설정 객체가 테스트와 여러 스레드에서 문제를 일으킵니다. 유일한 인스턴스와 전역 상태는 왜 다른 문제인가요?
잠깐, 답변을 보기 전에
먼저 내 말로 설명해 볼까요?
답변과 점검 포인트 펼치기답변 접기
구두 답변
정의를 외우기보다, 원리와 조건을 연결해 설명해 보세요.
싱글턴은 특정 타입의 인스턴스 생성과 접근을 하나로 제한하는 생성 방식이고, 전역 상태는 프로그램 여러 곳에서 공유하며 바꿀 수 있는 상태입니다. 싱글턴이 읽기 전용 설정을 담으면 전역 접근점이 될 수 있지만, 유일한 인스턴스라는 사실만으로 내부 필드의 동시 수정이나 공유 상태의 안전성이 보장되지는 않습니다. 반대로 일반 객체를 하나만 조립해 필요한 곳에 전달해도 전역 접근 없이 동일한 공유 효과를 만들 수 있습니다.
초기화에서는 두 스레드가 아직 값이 없는 시점에 동시에 생성해 인스턴스가 둘이 되거나, 한 스레드가 완전히 초기화되지 않은 객체를 볼 위험을 막아야 합니다. 언어가 제공하는 정적 초기화나 안전한 지연 초기화를 우선 사용하고, 직접 구현한다면 초기화와 공개 시점의 메모리 가시성을 확인하겠습니다. 초기화가 한 번 안전하다는 것과 이후 setConfig() 같은 메서드가 여러 스레드에서 안전하다는 것은 별개입니다. 후자는 불변 스냅샷, 락, 원자적 교체 같은 내부 동기화가 필요합니다.
싱글턴은 호출부가 구체 전역 객체를 직접 찾게 만들어 숨은 의존성, 테스트 간 상태 누수, 초기화 순서 문제를 키울 수 있습니다. 로그 sink나 프로세스 전체에서 정말 하나여야 하는 자원처럼 소유권이 명확한 경우에도 핵심 코드에는 생성 시 의존성을 전달하는 편을 우선 검토하겠습니다. 유일성보다 전역 변경 가능성과 생명주기·종료 정책이 더 큰 문제인지 분리해서 판단하겠습니다.
생성 안전성과 변경 안전성을 나눕니다
정적 초기화나 안전한 lazy 초기화는 두 스레드가 인스턴스를 중복 생성하거나 불완전한 객체를 보는 문제를 줄입니다. 그러나 이후 setConfig()가 여러 스레드에서 실행되면 생성이 한 번뿐이어도 필드가 섞이거나 독자가 중간 상태를 볼 수 있습니다. 검증된 불변 스냅샷을 원자적으로 교체하거나 락으로 변경을 보호하고, 생성자 예외가 잘못된 객체를 캐시하지 않는지도 정합니다. 프로세스 하나의 싱글턴은 다른 프로세스의 유일성을 만들지 않습니다.
전역 접근 대신 수명을 조립합니다
GlobalConfig.instance()를 호출부가 직접 찾으면 테스트 사이 상태와 초기화 순서가 숨습니다. 시작점에서 설정 객체 하나를 만들고 서비스에 전달하면 프로세스 내 공유는 유지하면서 테스트마다 다른 값을 넣고 종료 시 소유권을 닫을 수 있습니다. 로그 sink처럼 하나가 적합한 자원도 핵심 정책이 전역을 직접 찾지 않게 합니다. 병렬 초기화, 설정 교체, 테스트 격리, 종료 flush와 다중 프로세스 조정이 각각 어느 범위의 문제인지 분리해 검증하겠습니다.
구체적인 경계 사례
객체 하나를 안전하게 초기화한 뒤 두 스레드가 내부 카운터를 동시에 증가시키면 read-modify-write 경쟁은 그대로입니다. 반대로 불변 설정을 여러 인스턴스로 복사해도 공유 변경이 없으면 안전할 수 있습니다. 인스턴스 수와 동시성 안전성은 독립적인 축이므로 '하나라서 안전하다'는 판단을 하지 않습니다.
종료 순서도 전역 객체에서는 숨기 쉽습니다. 다른 객체의 소멸 과정이 이미 닫힌 전역 로그 sink를 호출하면 종료 중 오류가 납니다. 명시적인 상위 소유자가 작업을 먼저 멈추고 로그를 마지막에 닫도록 조립하면 수명을 추적하기 쉽습니다. 테스트마다 전역 상태를 초기화하는 방식은 병렬 테스트와 경쟁하므로 새로운 객체 그래프를 만드는 편이 격리에는 유리합니다.
득점 포인트
이해가 드러나는 지점을 확인해 보세요.
- 싱글턴의 유일한 생성과 전역 가변 상태의 동시성·격리를 구분한다.
- 초기화 안전성과 이후 설정 교체·메모리 가시성·종료 수명을 나눈다.
- 컴포지션 루트의 공유 객체와 분산 유일성의 범위를 설명한다.
감점 포인트
놓치기 쉬운 조건과 오해를 짚어 보세요.
- 싱글턴이면 내부 가변 상태와 메서드도 자동으로 thread-safe하다고 한다.
- 정적 초기화가 테스트 상태 누수와 종료 flush까지 해결한다고 말한다.
- 프로세스 하나의 인스턴스가 여러 프로세스의 유일한 소유권을 보장한다고 착각한다.
더 파고들 거리
하나 더 질문하며 이해의 범위를 넓혀 보세요.
- 공유 객체를 지연 초기화합니다. 생성자 예외·불완전 공개·동시 첫 접근은 어떻게 처리하나요?
- 싱글턴 전역 캐시를 테스트마다 초기화하는 것과 새 인스턴스를 주입하는 것의 비용은 무엇인가요?
- 여러 프로세스가 같은 자원을 하나만 사용해야 할 때 싱글턴 대신 어떤 조정 장치가 필요한가요?
득점·감점 포인트는 학습용 자기 점검 기준이며, 특정 회사의 실제 채점표가 아닙니다.
원리부터 공부하고 싶다면
답변을 보충하는 개념·예제·슈도코드를 읽어 보세요.