회사 프로젝트 중 싱글톤 패턴을 활용해 코드를 짜고 있었다. 스프링에서는 기본적으로 싱글톤 패턴을 제공해주고 있지만 직접 구현하고 쓰는 건 처음이다. 싱글톤 패턴이란 객체의 인스턴스가 오직 1개만 생성되는 패턴을 의미하며 이런 정의는 모두나 알고 있지만 구체적으로 어떻게 쓰이는지, 또 여러 방식으로 쓰이지만 각 방식에 있어서 장단점이 무엇인지 알게된 뿌듯한 시간이었다.
1. Eager Initialization
우선 가장 간단한 방식으로 Eager Initialization 방식이 있다. 코드부터 보도록 하자
public class VoteUtil {
private static VoteUtil instance = new VoteUtil();
private VoteUtil() {}
public static VoteUtil getInstance() {
return instance;
}
}
우선 static으로 VoteUtil 인스턴스를 선언한 것을 볼 수 있다. 위 방식대로 하면 클래스 로더에 의해 클래스가 로딩될 때 싱글톤 객체가 생성된다. static으로 클래스가 최초 로딩될 때 객체가 생성되므로 Thread-Safe 하다는 장점이 있다.
하지만, 싱글톤 객체의 사용유무와 관계없이 클래스가 로딩되는 시점에 항상 싱글톤 객체가 생성되고, 메모리를 잡고 있기 때문에 비효율적일 수 있다.
2. Lazy Initialization
Eager Initialization 방식에 단점을 보완하고자 Lazy Initialization 방식을 도입했다.
public class VoteUtil {
private static VoteUtil instance;
private VoteUtil(){}
public static LazyInitialization getInstance() {
if(instance == null) {
instance = new VoteUtil();
}
return instance;
}
}
이렇게 싱글톤 패턴을 적용하게 되면, 클래스가 로딩되는 시점이 아닌 클래스의 인스턴스가 사용되는 시점에 싱글톤 인스턴스를 생성한다. 즉 사용시점까지 싱글톤 객체 생성을 미루기 때문에 사용하기 전까지 메모리를 점유하지 않는다. 하지만 instance == null로 중복 생성을 막았지만 multi-thread 환경에서 두번 생성될 여지가 있다. 즉, multi-thread 환경에서는 싱글톤 철학이 깨질 수 있는 위험이 있다는 단점이 있다.
3. Thread Safe Lazy Initialization
Lazy Initialization 방식에서 thread-safe 하지 않다는 단점을 보완하기 위해 synchronized 키워드를 도입했다.
public class VoteUtil {
private static VoteUtil instance;
private VoteUtil(){}
public static synchronized LazyInitialization getInstance() {
if(instance == null) {
instance = new VoteUtil();
}
return instance;
}
}
synchronized 키워드를 사용할 경우, 자바 내부적으로 해당 영역이나 메소드를 lock, unlock 처리하기 때문에 thread-safe 하다는 장점이 있지만 이 과정에서 성능저하가 발생한다.
4. Initialization on demand holder idiom
public class VoteUtil {
private VoteUtil(){}
private static class InnerInstanceClass {
private static final VoteUtil instance = new VoteUtil();
}
public static VoteUtil getInstance() {
return InnerInstanceClass.instance;
}
}
VoteUtil 안의 innerClass InnerInstanceClass를 두면, getInstance() 메소드가 호출되기 전까지는 참조되지 않으며 메소드가 호출되면 static으로 선언된 instance를 한번만 호출하고 final을 통해 다시 값이 할당되지 않도록 한다. 즉 위의 모든 단점을 보완한 방법이다.
이렇게 싱글톤(Singleton) 패턴에 대해서 알아봤다. 각 방식이 어떻게해서 도입된 방식이고 장단점을 분석해보며 한층 이해도가 깊어진 느낌:)
'구현' 카테고리의 다른 글
[구현] BaseTimeEntity로 불필요한 코드 줄이기 (JPA) (0) | 2023.11.08 |
---|---|
[구현] 애플 소셜로그인 탈퇴 / SpringBoot (0) | 2023.07.28 |
[구현] 푸시알림(FCM) / SpringBoot (0) | 2023.06.17 |