[디자인 패턴] 싱글톤 패턴 (Singleton Pattern)

최진민·2021년 11월 14일
0

디자인 패턴

목록 보기
4/10
post-thumbnail
  • 정의
  • 구현
  • 예제

🏐 1. 싱글톤 패턴?

  • 싱글톤 패턴 (Singleton Pattern)
    • 전역 변수를 사용하지 않고 객체의 인스턴스를 단 하나만 생성하도록 보장하여, 프로그램 어디에서든 하나의 인스턴스만 접근하도록 하는 디자인 패턴
    • 필요성
      • 메모리 낭비 방지
      • 멀티 스레드 환경에서 같은 인스턴스를 공유하여 사용할 수 있기 때문에 요청이 많은 곳에서 사용할 때 이점이 있다.


⚽️ 2. 구현

  • public static final

    public class BasicSingleton {
        public static final BasicSingleton instance = new BasicSingleton();
    
        public BasicSingleton(){}
    }
    • static은 클래스를 로더(로딩 -> 링크 -> 초기화)할 때, 초기화 과정에서 static과 관련된 변수들의 값을 메모리에 할당한다.
    • 위와 같은 방식은 static 영역이 로딩될 때, 최초 한 번만 호출되기 때문에, 프로그램 전체에서 단 한 개의 객체라는 것을 보장한다. (Thread Safe)
    • final : 변경 불가능 하도록 한다.
    • private 생성자가 있는 이유는 클래스에 정의된 생성자가 없을 경우 자동 생성되기 때문입니다.
  • 정적 팩토리 (=> static factory method)

    1. Eager Loading

      public class Singleton2 {
          private static final Singleton2 singleton = new Singleton2();
      
          private Singleton2() {}
      
          public static Singleton2 getInstance() {
              return singleton;
          }
      }
      • getInstance()를 통해 항상 같은 객체의 참조를 반환 => 싱글톤 보장 (Thread Safe)
      • public static final 방식에 비해 API 변경에 유연
    2. Lazy Loading

      public class Singleton3 {
          private static Singleton3 singleton3;
      
          private Singleton3() {}
      
          public static Singleton3 getInstance() {
              if (singleton3 == null) {
                  singleton3 = new Singleton3();
              }
              return singleton3;
          }
      }
      • Lazy Loading은 호출 필요성에 따라 로딩이 되는 것을 의미

      • 컴파일 시점에 인스턴스를 생성하는 것이 아니라 인스턴스를 호출하는 시점에 생성된다. (동적 바인딩을 통한 인스턴스 생성)

      • getInstance()를 위와 같이 구현하면 Non-Thread Safe하기 때문에 아래와 같이 synchronized 키워드를 통해 멀티 스레드 환경에서도 안전하게 만들어야 한다.

        public static synchronized Singleton3 getInstance() {
          if (singleton3 == null) {
            singleton3 = new Singleton3();
          }
          return singleton3;
        }
        • But, 성능이 낮아진다.
    3. Lazy Loading 성능 완화

      public class Singleton4 {
          private static volatile Singleton4 singleton4;
      
          private Singleton4() {}
      
          public static Singleton4 getInstance() {
              if (singleton4 == null) {
                  synchronized (Singleton4.class) {
                      if (singleton4 == null) {
                          singleton4 = new Singleton4();
                      }
                  }
              }
              return singleton4;
          }
      }
      • 동기화 블럭 방식을 개선한 DCL (Double Checking Locking) 방식
      • 인스턴스가 생성되지 않았을 경우에만 synchronized 활용
  • 열거형 (Enum)

    public enum SingletonEnum {
        SINGLETON_ENUM
    }
    • public static final과 같은 방식이지만, 보다 간결한 방법
    • 주의 : 싱글톤이 ENUM 외 클래스를 상속받을 때 사용 불가


🏉 3. 예제

  • 가장 보편화 된 싱글톤 구현 방식은 정적 팩토리 방식 - Lazy Loading 방식.

    public class Client {
        public static void main(String[] args) {
            for (int i = 0; i < 5; i++) {
                Singleton3 singleton3 = Singleton3.getInstance();
                System.out.println(singleton3.toString());
            }
        }
    }
    • 위와 같이 구현 했을 때, 매번 같은 인스턴스를 호출하는지 확인할 수 있다. (싱글 스레드 환경)

      singleton.Singleton3@3f0ee7cb
      singleton.Singleton3@3f0ee7cb
      singleton.Singleton3@3f0ee7cb
      singleton.Singleton3@3f0ee7cb
      singleton.Singleton3@3f0ee7cb
    • 참고 : Thread in JAVA

  • 구현 : https://github.com/JinMinChoi/Design-Pattern

profile
열심히 해보자9999

0개의 댓글