본문 바로가기

잡다한 개발잡담

디자인 패턴 - 싱글톤 패턴(Singleton Pattern) - 2

싱글톤을 구현할 때 중요하게 생각해야 하는 것은 Thread-safe의 보장입니다. 멀티 스레드 환경에서 thread-safe를 보장하지 못한다면 제대로 된 동작을 수행하지 못합니다.

싱글톤 패턴의 공통 구현 특성
private 생성자와 static method를 사용한다는 것

Eager Initialization(이른 초기화, thread-safe)

이른 초기화 방식은 클래스 로더가 초기화하는 시점에서 정적 바인딩을 통해 해당 인스턴스를 메모리에 등록하여 사용하는 것입니다.(static의 특징을 활용)

클래스 로더에 의해 클래스가 처음 로딩되는 시점에 메모리에 로드하기 때문에 Thread-safe를 보장하게 됩니다.

Lazy Initialization with synchronized (게으른 초기화 with 동기화 블록, thread-safe)

synchronized 키워드를 이용한 게으른 초기화 방식으로도 thread-safe하게 구현할 수 있습니다. 컴파일 시점에 인스턴스를 생성하지 않는 동적 바인딩(런타임)을 통해 필요한 때에 인스턴스를 생성해서 사용합니다.

이 방식의 단점은 synchronized 동기화 블럭이 인스턴의 생성 유무에 상관없이 무조건 시행되어야 한다는 것으로 성능 저하의 문제가 필연적으로 발생합니다.

Lazy Initialization Double Checked Locking(DCL, thread-safe)

위의 게으른 초기화의 성능 저하 문제를 해결하기 위한 방식으로 DCL이 있다. 인스턴스가 생성되지 않은 경우에만 동기화 블록을 사용한다.

또한 volatile 키워드가 처음 사용된 것을 알 수 있는데, 멀티쓰레딩에서 singleton 변수의 싱글턴 인스턴스로 올바르게 초기화하는 과정이 진행될 수 있도록 한다.(volatile를 사용하게 되면 CPU cache가 아닌 main memory에서 값을 저장하고 읽어오므로 변수 값의 불일치 문제가 발생하지 않게 된다.)

Lazy Initialization. LazyHolder(게으른 홀더, thread-safe)

가장 많이 사용되는 싱글톤의 구현 방법입니다. 구현하는 방법은 private inner static class로 싱글톤 인스턴스를 지니게 합니다. 그러나 클래스가 로딩되는 시점에 바로 인스턴스를 생성하는 것이 아니라 getInstance() 매서드가 호출될 때, JVM 메모리에 로드되고 인스턴스를 생성하는 방식입니다. synchronized를 사용하지 않으므로 성능 저하의 문제를 해결한 방식입니다.