생성 - 1. Singleton

mskimdev·2026년 5월 19일

Design Pattern

목록 보기
1/13

Singleton 패턴

new DatabaseConnection()
new DatabaseConnection()
new DatabaseConnection()

이 코드가 문제인 이유를 처음엔 잘 모를 수 있다. DB 연결을 매번 새로 만들면 메모리도 낭비고, 연결 수도 무한정 늘어난다. 하나만 만들어서 계속 재사용하면 되는데, 그걸 보장하는 방법이 Singleton이다.


Singleton 패턴이란

인스턴스를 딱 하나만 생성하고, 어디서든 그 하나를 공유해서 쓰는 패턴이다.

애플리케이션 전체에서 하나만 존재해야 하는 객체에 적합하다. 대표적으로 DB 연결, 로그 시스템, 설정(Config) 객체 같은 것들이다.


기본 구현

public class AppConfig {
    // 클래스 자신을 담는 static 변수
    private static AppConfig instance;

    // 외부에서 new 못 하게 막음
    private AppConfig() {}

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

    public String getDbUrl() {
        return "jdbc:mysql://localhost:3306/mydb";
    }
}
AppConfig config1 = AppConfig.getInstance();
AppConfig config2 = AppConfig.getInstance();

System.out.println(config1 == config2); // true — 같은 객체

핵심은 세 가지다.

  • private static 변수로 인스턴스를 직접 보관
  • private 생성자로 외부에서 new 하는 것을 차단
  • static 메서드로 인스턴스를 제공


멀티스레드 문제

위 구현에는 허점이 있다. 두 스레드가 동시에 getInstance()를 호출하면 instance == null 체크를 동시에 통과해서 인스턴스가 두 개 만들어질 수 있다.

이를 해결하는 가장 간단한 방법은 synchronized를 쓰는 것이지만, 호출마다 동기화 비용이 생긴다. 더 나은 방법은 클래스 로딩 시점에 인스턴스를 만들어버리는 것이다.

public class AppConfig {
    // 클래스가 로드될 때 바로 생성
    private static final AppConfig instance = new AppConfig();

    private AppConfig() {}

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

JVM은 클래스를 처음 로드할 때 static 필드를 초기화하는데, 이 과정은 스레드 안전이 보장된다. 인스턴스를 실제로 쓰기 전에 미리 만들어둔다는 뜻에서 Eager Initialization이라고 부른다.


언제 쓰는가

  • 전체 앱에서 하나만 존재해야 하는 자원 — DB 연결 풀, 설정 파일, 로거
  • 여러 곳에서 공유 상태를 유지해야 할 때

반대로, 상태를 많이 갖는 객체를 Singleton으로 만들면 테스트하기 어려워진다. Singleton은 전역 상태(global state)이기 때문이다. 꼭 필요한 곳에만 쓰는 것이 좋다.


Singleton의 핵심은 "생성을 통제한다"는 것이다. new를 막고 하나의 경로만 열어두는 것, 그게 전부다.

profile
<- 개발 공부하는 나

0개의 댓글