본문 바로가기

아키텍처

[디자인 패턴] 싱글톤 패턴 (Singleton Pattern)

728x90

/* 싱글톤 패턴 */

싱글톤 패턴이랑 단 클래스의 객체를 하나만 만들기 위한 코드 패턴이다

코드를 하다보면 우리는 하나의 객체만 사용할 때가 있다. (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을 이용하는 방법이 있다.

 

 

728x90

'아키텍처' 카테고리의 다른 글

[디자인 패턴] 프로토타입 패턴  (0) 2024.03.31
[아키텍처] SOLID 원칙  (0) 2024.02.09