싱글턴 패턴이란

  • 인스턴스가 사용될 때 똑같은 인스턴스를 생성하는 것이 아니라, 동일 인스턴스를 사용하게!
  • 메모리 낭비 방지
  • 싱글톤으로 만들어진 인스턴스는 전역적으로 사용되기 때문에 다른 클래스의 인스턴스들이 데이터를 공유할 수 있다.
  • 프로그램 상에서 동일한 커넥션 객체를 만드는 경우, 하나만 사용되어야 하는 객체를 만들어야 하는 경우 유용
  • but!
    싱글톤 인스턴스에게 많은 일을 위임하거나 너무 많은 데이터를 공유시키면 싱글톤 인스턴스와 다른 클래스 인스턴스들 간에 coupling이 많아지고 결합도가 높아져 개방폐쇄원칙에 위배

Eager initialization

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

  private Singleton() { }

  public static Singleton getInstance() {
    return instance;
  }
  • 생성자에 private 키워드를 붙여, new 키워드를 사용할 수 없게 되므로, 다른 클래스에서 new 키워드를 사용할 수 없다. -> 인스턴스 생성 불가.
    외부 클래스가 Singleton 클래스의 인스턴스를 가질 수 있는 방법은 getInstance() 메서드
    를 사용하는 것
  • but!
    클래스가 load되는 시점에 인스턴스를 생성시킨다는 단점 (사용되지 않더라도 load된다)

Lazy initialization

public class Singleton {
  private static Singleton instance;

  private Singleton() { }

  public static Singleton getInstance() {
    if (instacne == null) {
      instance = new Singleton();
    }
    return instance;
  }
}
  • 최초 사용 시점에만 인스턴스화시키기 때문에 프로그램이 메모리에 적재되는 시점에 부담이 많이 줄게 된다.
  • but!
    동일 시점에 getInstance() 메서드를 호출하면 인스턴스가 2번 생길 위험이 있기 때문에 프로그램이 multi thread 방식이라면 위와 같은 방식이 안전하지 않다.

Initialization on demand holder idiom

public class Singleton {
  private Singleton() { }

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

  public static Singleton getInstance() {
    return SingletonHolder.instance;
  }
}
  • 클래스 안에 클래스(holder)를 두어 JVM의 Class Loader 매커니즘과 class가 로드되는 시점을 이용한 방법. thread 간 동기화 문제를 해결할 수 있다.
  • 중첩 클래스 holder는 getInstance() 메서드가 호출되기 전에는 참조되지 않고, 최초로 getInstance() 메서드가 호출될 때 클래스 로더에 의해 싱클톤 객체를 생성하여 리턴.