CS/Design Patterns

1. 싱글톤 패턴

isTrue 2025. 4. 14. 21:42
반응형

싱글톤(Singleton) 패턴은 자바에서 가장 많이 사용되는 디자인 패턴 중 하나다.
한 번쯤은 "인스턴스를 하나만 만들고 싶다"라는 생각을 해봤다면, 싱글톤을 이미 직간접적으로 써봤을 수도 있다.

이 글에서는 싱글톤 패턴이 무엇이고, 왜 쓰는지, 그리고 어떻게 구현하면 좋은지를 처음부터 차근차근 정리해본다.

 

싱글톤이란?

간단히 말해,

"클래스의 인스턴스를 애플리케이션 전체에서 하나만 존재하도록 보장하는 패턴"이다.

설정 정보, 로그 기록기, 캐시 등 공통으로 쓰이고 하나만 있어야 하는 객체들에 주로 쓰인다.

 

왜 싱글톤을 쓸까?

  • 중복 인스턴스 방지
    → 동일한 객체를 여러 번 만들지 않아 메모리 낭비를 막을 수 있다.
  • 공유 상태 유지
    → 모든 코드에서 같은 객체를 참조하므로 설정값이나 상태가 일관된다.
  • 전역 접근
    → 어디서든 getInstance()를 통해 접근 가능하다.

 

싱글톤 구현 방법

자바에서 싱글톤을 구현하는 방법은 다양하다. 그중 대표적인 3가지 방법을 살펴보자.

1. Eager Initialization (즉시 초기화)

public class Singleton {
    private static final Singleton instance = new Singleton();

    private Singleton() {}

    public static Singleton getInstance() {
        return instance;
    }
}

 

장점

  • 클래스가 로딩될 때 인스턴스를 생성하므로 스레드에 안전하다.

단점

  • 프로그램 시작 시 무조건 생성되기 때문에, 필요하지 않은 경우에도 메모리를 차지할 수 있다.

 

2. Lazy Initialization (지연 초기화 + 동기화)

public class Singleton {
    private static Singleton instance;

    private Singleton() {}

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

장점

  • 인스턴스가 필요한 시점에 생성된다.

단점

  • synchronized 키워드로 인해 매번 락을 획득해야 하므로 성능이 떨어질 수 있다.

 

3. Double-Checked Locking + volatile (권장 방식)

public class Singleton {
    private static volatile Singleton instance;

    private Singleton() {}

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

 

장점

  • 인스턴스가 필요할 때만 생성되고,
  • 첫 호출 이후에는 synchronized 블록을 타지 않아 성능 저하도 없다.

volatile 키워드를 쓰는 이유?

  • 자바의 메모리 모델 상, 객체 생성 시 명령어 재정렬(Instruction Reordering) 이 일어날 수 있는데,
    volatile을 쓰면 이를 방지할 수 있다.
    더보기
    참고:
    자바 객체생성은
    1. 메모리 할당
    2. 생성자 호출
    3. 변수에 참조할당
    순으로 이뤄지는데, 컴파일러나 CPU가 명령어 재정렬(Instruction Reordering) 을 하게 되면 다음처럼 바뀔 수 있다.

    메모리 할당 → 변수에 참조 할당 → 생성자 호출 

    그럼 다른 스레드가 instance != null이 되는 걸 보고 미리 접근해버릴 수 있다! → 생성자도 안 끝났는데 객체 사용
  • 또한 한 스레드의 변경 내용을 다른 스레드가 바로 인식할 수 있도록 가시성(visibility) 도 보장해준다.

정리

구현 방식  스레드 안전 성능 특징
Eager O 좋음 항상 생성됨
Lazy + synchronized O 나쁨 락 오버헤드
Double-Checked + volatile O 좋음 가장 실무에 적합

 

싱글톤은 간단하지만, 멀티스레드 환경을 고려하지 않으면 의도치 않게 여러 인스턴스가 만들어질 수 있다.
특히 토큰 관리, 설정 공유, 전역 상태 관리 같은 기능을 구현할 땐 반드시 신중하게 설계해야 한다.

요즘은 Spring 프레임워크처럼 싱글톤을 자동으로 관리해주는 환경도 많지만,
기본 원리를 정확히 알고 있어야 내부에서 어떤 일이 일어나는지 이해할 수 있다.

 

 

반응형

'CS > Design Patterns' 카테고리의 다른 글

커맨드 패턴(Command Pattern)  (0) 2025.04.29