싱글톤 패턴

theonde·2022년 11월 14일
0

인스턴스를 오직 한개만 제공하는 클래스

public class Settings {

    private static Settings instance;

    private Settings() {}

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

@Test
void singleTon() {
    Settings settings = Settings.getInstance();
    Settings settings1 = Settings.getInstance();

    assertThat(settings == settings1).isTrue();
}
  • 하나의 객체를 공유한다.

동시성 보장하기

  • 위 코드는 thread-safe하지 않다.

1. synchronized 사용

public class Settings {

    private static Settings instance;

    private Settings() {}

    public static synchronized Settings getInstance() {
         if (instance == null) {
            instance = new Settings();
        }
        return instance;
    }
}
  • 동기화 매커니즘(Lock)때문에 성능 저하를 유발할 수 있다.

2. 이른 초기화(eager initialization) 사용

  • 미리 인스턴스를 초기화 하는 방법
public class Settings {

    private static final Settings INSTANCE = new Settings();

    private Settings() {}

    public static Settings getINSTANCE() {
        return INSTANCE;
    }
}

3. double checked locking

  • null체크를 두번 한다.
public class Settings {

    private static volatile Settings instance;

    private Settings() {}

    public static Settings getINSTANCE() {
        if (instance == null) {
            synchronized (Settings.class) {
                if (instance == null) {
                    instance = new Settings();
                }
            }
        }
        return instance;
    }
}
  • 인스턴스가 null인 경우에만 동시성 체크를(syncronized) 하게 된다. (성능 최적화)

4. static inner 클래스 사용

public class Settings {

    private Settings() {}

    private static class SettingsHolder {

        private static final Settings INSTANCE = new Settings();
    }

    public static Settings getInstance() {
        return SettingsHolder.INSTANCE;
    }
}

안전하게 싱글톤 사용하기

  • 리플렉션, 직렬화 & 역직렬화 등을 사용하면 싱글톤 패턴이 깨질 수 있다.

  • enum을 사용하면 싱글톤 패턴을 안전하고 단순하게 구현할 수 있다.

public enum SettingsEnum {

    INSTANCE;
}

@Test
void enumSingleTon() {
    SettingsEnum settings = SettingsEnum.INSTANCE;
    SettingsEnum settings1 = SettingsEnum.INSTANCE;

    assertThat(settings == settings1).isTrue();
}
  • enum은 리플렉션에서 newInstance()를 할 수 없다. (리플렉션을 사용하더라도 싱글톤이 보장된다.)

  • 단점은 enum은 애플리케이션 로딩 시점에 인스턴스가 생성된다. (로딩 시점에 생성해놓고 사용하지 않는다면 리소스에 낭비가 생길 수 있다.)

  • serializable을 구현하고 있다.

  • 상속을 사용할 수 없다. (인터페이스 구현은 가능)

상속이 필요하고, 지연 로딩까지 하고 싶은 경우 static inner 클래스를 사용하는 것이 좋다.

스프링 컨테이너에서의 싱글톤 스코프

  • 스프링 컨테이너에서는 모든 인스턴스가 싱글톤 객체로 관리된다.

  • 스프링 컨테이너는 엄밀히 따지자면 싱글톤 패턴이 아니라 싱글톤 스코프다.

    • 스프링 컨테이너 내부에서는 싱글톤으로 관리 되지만, 얼마든지 직접 새로운 객체를 생성할 수 있기 때문에 엄밀히 따지자면 싱글톤 패턴이 아니다.
profile
개발자ㅋ.ㅋ

0개의 댓글