JAVA
Singleton 구현 기법
devchive
2023. 8. 27. 20:18
Singleton 패턴
생성자가 여러 차례 호출되더라도 실제로 생성되는 객체는 하나이고 최초 생성 이후에 호출된 생성자는 최초의 생성자가 생성한 객체를 리턴한다.
기본적인 Singleton 패턴
public class Singleton {
private static Singleton instance;
private Singleton(){}
public static Singleton getInstance(){
if(instance == null){
instance = new Singleton();
}
return instance;
}
}
Singleton의 getInstance를 호출할때 instance가 없다면 만들어주고 있다면 만들어둔 instance를 return 해준다. 이 코드는 스레드가 여러개일때 문제가 생길 수 있다. Tread A 와 Thread B가 동시에 instance == null 을 최초 검사한다면 두 스레드에서 instance를 각각 생성하여 instance가 두개가 될 수 있다.
synchronized를 이용한 패턴
public class Singleton {
private static Singleton instance;
private Singleton(){}
public static synchronized Singleton getInstance() {
if(instance == null) {
instance = new Singleton();
}
return instance;
}
}
위의 기본적인 패턴의 문제점을 해결하기 위해 synchronized 키워드를 넣었다. 이 경우 instance 생성은 스레드가 여러개이더라도 한번만 생성된다. 하지만 getInstance를 할때마다 불필요한 lock이 걸려 성능상 문제가 있을 수 있다.
DCL (Double Checked Locking) 패턴
public class Singleton {
private static Singleton instance;
private Singleton(){}
public static Singleton getInstance() {
if(instance == null) {
synchronized (Singleton.class) {
if(instance == null) {
instance = new Singleton();
}
}
}
return instance;
}
}
위 synchroinzed 패턴의 성능을 향상시키기 위해 생성해주는 부분만 synchronized block 으로 실행시켜준다.
static 초기화를 이용한 패턴
public class Singleton {
private static Singleton instance = new Singleton();
private Singleton(){}
public static Singleton getInstance() {
return instance;
}
}
최초 instance 생성을 getInstance 호출 시점이 아닌 클래스 가 로딩되는 시점에 생성해주는 방식이다. 간결하고 Thread-safe하다. 하지만 사용할지 안할지 모르는 instance를 미리 만들어두는것이 옳은것인가에 대한 문제가 있다.
LazyHolder 패턴
public class Singleton {
private Singleton(){}
public static Singleton getInstance() {
return LazyHolder.INSTANCE;
}
private static class LazyHolder {
private static final Singleton INSTANCE = new Singleton();
}
}
이 방법은 static 영역에서 초기화를 하지만 실제 getInstance로 LazyHolder를 참조할때 class가 로딩되며 초기화가 진행된다.