/* 싱글톤 패턴 */
싱글톤 패턴이랑 단 클래스의 객체를 하나만 만들기 위한 코드 패턴이다
코드를 하다보면 우리는 하나의 객체만 사용할 때가 있다. (DB에 연결하기 위한 Connection 클래스 - 여러 클래스에서 Connection 클래스를 이용할때마다 객체를 여러번 만들면 메모리 낭비가 심하다)
/* 이해를 위한 예시 */
public class Main{
public static void main(String[] args){
Singleton s1 = Singleton.getInstance();
Singleton s2 = Singleton.getInstance();
System.out.println(s1 == s2); //true
}
}
getInstance() 메서드를 이용해 객체를 불러온다. 싱글톤 패턴을 통해 객체를 하나만 만들어서 쓰고 있으므로 s1 과 s2는 똑같은 객체 주소를 참조하는 것을 알 수 있다.
/* 싱글톤 만드는 방법 1 - Eager Initialization */
class Singleton {
private static final Singleton INSTANCE = new Singleton();
private Singleton(){} // 생성자를 private으로 선언. 외부에서 사용 제한
public static Singleton getInstance(){
return INSTANCE;
}
}
/* 싱글톤 만드는 방법2 - Lazy Initialization */
class Singleton {
private static Singleton instance;
private Singleton(){} // 생성자를 private으로 선언. 외부에서 사용 제한
public static Singleton getInstance(){
if(instance == null){
instance = new Singleton():
}
return instance;
}
}
위에 둘 (EAGER, LAZY)의 차이가 보이는가? EAGER 기법은 메서드 밖에 new Singleton()을 생성했으므로 static의 특성상 런타임시 즉시 생성이 된다. 하지만 당장 해당 객체를 사용하지 않더라도 메모리에 남아있기 때문에 메모리 낭비가 발생할 수 있다. LAZY 기법은 메서드를 호출했을 때 static 객체를 생성하고 이미 생성했으면 기존의 객체를 반환한다. 객체 생성에 대한 관리를 내부적으로 처리한다.
하지만 LAZY 기법은 멀티 스레드 환경에서 취약하다. 스레드가 if문을 평가하고 new Singleton()코드를 아직 실행하지 않았을 때 다른 스레드 또한 if문을 평가할 수 있다. 이 때 두 스레드 환경에서 모두 if문에서 인스턴스가 null이라고 평가를 했기 때문에 Singleton 객체가 두개가 생성되는 예상하지 못한 결과를 얻을 수 있다.
이를 막기 위해 synchronized 키워드를 사용할 수 있다. (동기작업) 하지만 overhead가 발생할 수 있다.
권장되는 방법이 있는데
LazyHolder, Enum을 이용하는 방법이 있다.
'아키텍처' 카테고리의 다른 글
[디자인 패턴] 프로토타입 패턴 (0) | 2024.03.31 |
---|---|
[아키텍처] SOLID 원칙 (0) | 2024.02.09 |