
하나의 웹 서비스가 있다고 가정을 해보자 해당 서비스에는 사용자가 접속 시 인사말을 출력해주는 WelcomeService가 존재한다. 접속자 수가 적을때는 요청마다 WelcomeService를 생성하여 인사말을 출력해주는것이 가능하지만 접속자수가 많아지면 매 요청에 대하여 WelcomeService를 생성하는것은 리소스를 많이 요구한다.
이때 Singleton Pattern을 사용 할 수 있다. 해당 패턴은 사용자의 요청이 오기 전에 미리 1개의 WelcomeService를 생성해 놓고 사용자가 요청을 하면 미리 생성된 WelcomeService에서 해당 요청을 처리한다.
간단히 요약하면 Singleton Pattern은 객체의 인스턴스를 1개만 생성하는 패턴이다.
- 객체를 하나만 생성하여 메모리를 보다 효율적으로 관리 할 수 있다.
- 미리 인스턴스를 생성하여 기존의 방법보다 요청 처리속도가 빠르다.
- 해당 패턴으로 생성된 객체의 인스턴스의 전역이기때문에 다른 객체의 인스턴스들이 데이터를 공유하기 쉽다.
- 싱글톤 인스턴스를 사용하는 객체들은 모두 해당 인스턴스에 의존하기에 재사용성이 떨어지고 테스트하기 어렵다.
- 싱글톤 인스턴스들은 모두 전역이기에 다른 클래스에서 싱글톤 인스턴스의 값을 변경하면 싱글톤 클래스를 사용하든 모든 클래스에 영향을 끼친다.
- 기본생성자를 사용할 수 없기에 상속이 불가능하다.
class Singleton {
private static Singleton singleton = new Singleton();
private Singleton() {}
public static Singleton getInstance() {
return singleton;
}
}
class Singleton {
private static Singleton singleton;
private Singleton() {} //생성자에 접근 x
static {
try {
singleton = new Singleton();
} catch (Exception e) {
throw new RuntimeException("Exception occured in creating singleton instance");
}
}
public static Singleton getInstance() {
return singleton;
}
}
Static Bolck은 초기화 블록(Initialization Block)이라고 불리며 클래스가 처음 로딩될 때 한 번만 수행되는 블록을 의미한다. 잘 사용하지는 않지만 클래스 변수의 복잡한 초기화에 사용된다. 비슷한 개념으로 Instance Block이 존재한다.
Static Block : 클래스가 로딩될때 한번만 수행
Instance Block : 인스턴스가 생성될때마다 수행
class Singleton {
private static Singleton singleton;
private Singleton() {}
public static Singleton getInstance() {
if (singleton == null) singleton = new Singleton();
return singleton;
}
}
class Singleton {
private static Singleton singleton;
private Singleton() {}
public static synchronized Singleton getInstance() {
if (singleton == null) singleton = new Singleton();
return singleton;
}
}
Double Checked Locking 방식은 객체가 null 일 경우에만 synchronized가 실행되도록 하여 객체가 생성된 후에는 synchronized가 실행되지 않게하여 성능저하를 막을 수 있다.
class Singleton {
private static Singleton singleton;
private Singleton() {}
public static Singleton getInstance(){
if(singleton == null){
synchronized (Singleton.class) {
if(singleton == null) singleton = new Singleton();
}
}
return singleton;
}
}
class Singleton {
private Singleton() {}
private static class SingletonHelper {
private static final Singleton SINGLETON = new Singleton();
}
public static Singleton getInstance(){
return SingletonHelper.SINGLETON;
}
}
enum EnumSingleton {
INSTANCE;
public static void doSomething(){
//do something
}
}