본문 바로가기
Computing and DB 🖥/Computer Science

[디자인 패턴] 싱글톤 제 2장 - "싱글톤의 심화과정"

by dudefromkorea 2024. 1. 25.

지난 시간에는 싱글톤의 개념과 기본적인 구현 방법

멀티 쓰레드 환경에서 thread - safe 하게 구현하기

그리고 이른 초기화에 대해서 알아보았습니다

(지난 챕터, 싱글톤 제 1장 보러 가기)

 

 

이번 시간에는 JAVA 에서 권장하는 방법들과

더불어 1 장에서 다뤘던 개념들의 단점들을

보완하기 위해 나온 방안들을 살펴보겠습니다

 

 

Double Checked Locking

멀티 쓰레드 환경에서 이른 초기화처럼 객체를 미리 생성하지 않으면서

synchronized 의 성능 이슈 또한 사전에 방지할 수 있는 기법입니다

Double Checked Locking

public class GlobalSettings {
    private static volatile GlobalSettings instance;
    private GlobalSettings() {}

    public static GlobalSettings getInstance() {
        if (instance == null) { // 1st gate
            synchronized (GlobalSettings.class) { // 2nd gate
                if (instance == null) { // 3rd gate
                    instance = new GlobalSettings();
                }
            }
        }
        return instance;
    }
}

 

1st gate

instance 의 null 여부를 체크합니다

instance 가 이미 존재하는 경우(대부분의 경우)

synchronized 에 진입하지 않기 때문에 성능 저하에 대한 우려가 낮습니다

 

2nd gate

1st gate 를 통과했을 때만 진입합니다

synchronized 키워드를 이용하여 thread - safe 환경을 만들고

동기화를 위해 리터럴로 GlobalSettings.class 를 적습니다

 

3rd gate

1st gate, 2nd gate 를 통과했을 때만 진입합니다

synchronized 블록 안에서 다시 한번 instance 의 null 여부를 체크합니다

다른 쓰레드가 락을 넘겨주기 전에 instance 를 생성했을 수도 있는 경우를 대비합니다

 

 

Double Checked Locking 을 사용할 경우 멀티 쓰레드 환경에서 성능은 개선되지만

단점으로는 다소 복잡한 구현과 함께 JAVA 5 이상에서의 volatile 의 제한적인 메모리 모델이 언급됩니다

 

 

Static Inner Class (Initialization-on-demand holder idiom)

static inner class 를 사용하는 방법은 initialization on demand holder idiom 으로 알려져 있으며

클래스의 로딩과 초기화를 지연시키고

JVM 의 클래스 초기화 메커니즘을 통해 thread - safe 를 제공합니다

Static Inner Class (Initialization on demand holder idiom)

public class GlobalSettings {
    private GlobalSettings() {}

    private static class Holder {
        private static final GlobalSettings INSTANCE = new GlobalSettings();
    }

    public static GlobalSettings getInstance() {
        return Holder.INSTANCE;
    }
}

 

private 생성자

싱글톤의 기본 개념으로 생성자는 private 으로 선언합니다

따라서 인스턴스의 생성은 전적으로 클래스 내부에서 통제됩니다

 

Static Inner Class (Holder) - (Lazy Initialization)

Holder 클래스 내부에서 인스턴스가 생성됩니다

GlobalSettings.getInstance() 가 호출되기 이전에는

Holder 클래스가 로드되지 않으며 인스턴스 또한 생성되지 않습니다

이는 싱글톤의 인스턴스 생성을 지연시키는 효과를 지닙니다(lazy initialization)

 

Holder 클래스에서 static final 로 선언된 인스턴스는

JVM 차원에서 한 번만 수행되며 이후로는 동일한 인스턴스가 반환되므로

별도의  synchronized 키워드나 락이 필요하지 않습니다

 

Thread - safe

앞선 특징과 동일한 이유로 static final 필드의 초기화는

JAVA 클래스 초기화 메커니즘을 통해 thread - safe 하게 처리됩니다

 

 

 

오늘은 싱글톤의 심화적인 내용들을 다루어 보았습니다

다음 시간에는 다른 디자인 패턴을 가지고 찾아오도록 하겠습니다

728x90
반응형