본문 바로가기
Design Pattern

싱글턴 패턴(Singleton Pattern)

by 밍상 2023. 9. 25.

싱글턴 패턴은 클래스 인스턴스를 하나만 만들고, 그 인스턴스로의 전역 접근을 제공하는 방법입니다.

 

싱글턴? 단순히 객체 인스턴스 1개 만드는 방법 아니야?

맞습니다. 하지만 하나만 있어도 충분히 잘 돌아가는 객체가 많습니다.

스레드 풀, 캐시, 대화상자, 사용자 설정, 등등 이런 객체들은  1개여야 정상적으로 작동할 수 있죠.

 

정적 변수를 쓰면 되는 것 아닌가요?

싱글턴 패턴은 특정 클래스에 객체 인스턴스가 하나만 만들어지도록 해 주는 패턴입니다.

 

전역 변수에 어떤 단점이 있나요?

전역 변수에 객체를 대입하면 애플리케이션이 시작할 때 객체가 생성됩니다. 리소스가 큰 객체이지만, 만약 사용하지 않게 되면 자원만 잡아먹는 객체를 생성하게 된 꼴 입니다. -> 그러면 싱글턴 패턴은 필요할때 생성하는건가?

 

public class Singleton {

    private static Singleton uniqueInstance;

    private Singleton() {}

    public static Singleton getInstance(){
        if(uniqueInstance == null){
            uniqueInstance = new Singleton();
        }
        return uniqueInstance;
    }
}

이렇게 하면 getInstance가 호출되기 전까지는 인스턴스를 생성하지 않을 수 있어요.

이러한 방법을 게으른 인스턴스 생성(lazy instantiation)이라고 부른답니다.

 

멀티스레드 환경에서 싱글턴이 돌아가게 만들려면 어떻게 할까요?

1. synchronized getInsatnce() 를 사용한다.

2. 인스턴스가 필요할 때 생성하지 말고 처음부터 만듭니다.

3. DLC(Double-Checked Locking)을 사용해서 인스턴스가 생성돼 있는지 확인 후 생성되어 있지 않았을 경우에만 동기화할 수 있습니다. 이렇게 되면 처음에만 동기화, 그 이후에는 동기화가 필요 없죠.

 

public class DlcSingleton {

    private volatile static DlcSingleton uniqueInstance;

    private DlcSingleton() {
    }

    public static DlcSingleton getInstance() {
        if (uniqueInstance == null) {
            synchronized (Singleton.class) {
                if (uniqueInstance == null) {
                    uniqueInstance = new DlcSingleton();
                }
            }
        }
        return uniqueInstance;
    }
}

모든 메서드와 변수가 static으로 선언된 클래스를 만들어도 되지 않나요?

필요한 모든 내용이 클래스에 다 들어 있고, 복잡한 초기화가 필요 없는 경우에만 그 방법을 쓸 수 있습니다.

 

클래스 로더와 관련된 문제는 없나요?

클래스로더가 여러 개일때 따로 클래스 로더를 지정해주지 않으면 문제가 생길 수 있습니다.

 

리플렉션, 직렬화, 역직렬화 문제는 없나요?

있습니다. 조심히 사용해야 해요.

 

enum을 사용하면 싱글턴의 여러 문제점을 해결할 수 있는 것 아닌가요?

맞습니다. 지금까지의 getInstance() 메서드 구현 과정은 싱글턴 원리를 위한 학습이었습니다.

 

출처

에릭 프리먼, 엘리자베스 롭슨, 케이시 시에라, 버트 베이츠. 『헤드퍼스트 디자인패턴 개정판』. 한빛미디어, 2022