DEV Community

dss99911
dss99911

Posted on • Originally published at dss99911.github.io

Java 싱글톤 패턴 구현하기

Java 싱글톤 패턴 구현하기

싱글톤 패턴은 클래스의 인스턴스가 하나만 존재하도록 보장하는 디자인 패턴입니다.

Static 초기화 블록을 이용한 구현

클래스 로딩 시점에 인스턴스를 생성하는 방법입니다.

public class PhotoManager {

    private static final PhotoManager sInstance;
    private static final TimeUnit KEEP_ALIVE_TIME_UNIT;

    static {
        // 상수 초기화
        KEEP_ALIVE_TIME_UNIT = TimeUnit.SECONDS;

        // 싱글톤 인스턴스 생성
        sInstance = new PhotoManager();
    }

    // private 생성자
    private PhotoManager() {
        // 초기화 로직
    }

    public static PhotoManager getInstance() {
        return sInstance;
    }
}
Enter fullscreen mode Exit fullscreen mode

다양한 싱글톤 구현 방법

1. Eager Initialization (즉시 초기화)

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

    private Singleton() {}

    public static Singleton getInstance() {
        return INSTANCE;
    }
}
Enter fullscreen mode Exit fullscreen mode

장점: 간단하고 스레드 안전
단점: 사용하지 않아도 인스턴스 생성됨

2. Lazy Initialization with synchronized

public class Singleton {
    private static Singleton instance;

    private Singleton() {}

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

장점: 필요할 때만 생성
단점: 매번 동기화 오버헤드

3. Double-Checked Locking

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;
    }
}
Enter fullscreen mode Exit fullscreen mode

장점: Lazy + 효율적인 동기화
주의: volatile 키워드 필수 (Java 5+)

4. Initialization-on-demand Holder (권장)

public class Singleton {
    private Singleton() {}

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

    public static Singleton getInstance() {
        return Holder.INSTANCE;
    }
}
Enter fullscreen mode Exit fullscreen mode

장점:

  • Lazy initialization
  • 스레드 안전 (클래스 로딩 메커니즘 활용)
  • 동기화 오버헤드 없음

5. Enum Singleton (Effective Java 권장)

public enum Singleton {
    INSTANCE;

    public void doSomething() {
        // 메서드 구현
    }
}
Enter fullscreen mode Exit fullscreen mode

장점:

  • 직렬화 안전
  • 리플렉션 공격 방어
  • 가장 간결함

사용:

Singleton.INSTANCE.doSomething();
Enter fullscreen mode Exit fullscreen mode

구현 방법 비교

방법 Lazy 스레드 안전 직렬화 안전 복잡도
Eager X O X 낮음
Synchronized O O X 낮음
Double-Checked O O X 중간
Holder O O X 낮음
Enum X O O 낮음

직렬화 문제 해결

Enum 외의 방법에서 직렬화 시 새 인스턴스가 생성되는 것을 방지:

public class Singleton implements Serializable {
    private static final long serialVersionUID = 1L;
    private static final Singleton INSTANCE = new Singleton();

    private Singleton() {}

    public static Singleton getInstance() {
        return INSTANCE;
    }

    // 역직렬화 시 기존 인스턴스 반환
    protected Object readResolve() {
        return INSTANCE;
    }
}
Enter fullscreen mode Exit fullscreen mode

권장사항

  1. 대부분의 경우: Holder 패턴 사용
  2. 직렬화가 필요한 경우: Enum 싱글톤 사용
  3. Spring 환경: 스프링 빈으로 관리 (기본이 싱글톤 스코프)

주의사항

  • 싱글톤은 전역 상태를 만들어 테스트를 어렵게 할 수 있습니다.
  • 가능하면 의존성 주입(DI)을 고려하세요.
  • 멀티스레드 환경에서는 상태 관리에 주의하세요.

Originally published at https://dss99911.github.io

Top comments (0)