싱글톤 패턴의 정의는 객체의 인스턴스를 오직 1개만 생성하고 생성된 객체를 어디서든지 참조할 수 있도록 하는 패턴이다.
public class SingleTon {
private static SingleTon singleton_instance = null;
//1.
private SingleTon() {}
public static SingleTon getInstance() {
//2.
if(singleton_instance == null){
singleton_instance = new SingleTon();
}
//3.
return singleton_instance;
}
}
하지만 위 방법으로는 멀티 쓰레드 환경에서 안전하지 않다. 왜냐하면 멀티쓰레드에서 if문을 동일하게 동작할 수 있어 new SingleTon()이 여러번 호출 될 수 있습니다.
public class SingleTon {
private static SingleTon singleton_instance = null;
private SingleTon() {}
public static synchronized SingleTon getInstance() {
if(singleton_instance == null){
singleton_instance = new SingleTon();
}
return singleton_instance;
}
}
synchronized키워드를 사용하여 Thread-safe하게 구현할 수 있지만 해당 메소드를 호출할 때마다 동기화처리를 해야하므로 성능 부하가 발생합니다.
그리고 instance변수에 이미 객체가 생성되어 있음에도 불구하고 메소드를 호출할 때 synchronized키워드로 인해 락이 걸릴 수 있어 Double Checked Locking Pattern을 사용하는게 바람직하다.
public class SingleTon {
private static volatile SingleTon singleton_instance = null;
private SingleTon() {}
public static SingleTon getInstance() {
if(singleton_instance == null){
synchronized (SingleTon.class) {
if(singleton_instance == null) {
singleton_instance = new SingleTon();
}
}
}
return singleton_instance;
}
}
instance변수가 비어있을 경우(if문 안에서)에만 synchronized블럭을 사용해 double checked locking을 사용해 효율적으로 처리 가능하다.
단, instance변수에 volatile키워드를 사용해야 한다.
public class SingleTon {
private SingleTon() {}
//static inner class사용
private static class SingleTonHolder{
private static final SingleTon SINGLE_TON_INSTANCE = new SingleTon();
}
public static SingleTon getInstance() {
return SingleTonHolder.SINGLE_TON_INSTANCE;
}
}
위 방법을 많이 사용하는데 그 이유는 아래와 같다.
싱글톤 패턴이 무엇인지 검색하고 알아본 결과 싱글톤 패턴은 안티패턴이라고 불릴 만큼 단독으로 사용한다면 객체지향원칙(SOLID)에 위반되는 사례가 많고, 스프링 프레임워크를 사용할 시 싱글톤 패턴의 문제점들을 보완하면서 장점의 혜택을 누릴 수 있으니 잘 살펴보고 적용해야 될 듯 하다.