따봉도치야 고마워

Head First Design Patterns : (5)싱글턴 패턴 본문

프로그래밍/공부

Head First Design Patterns : (5)싱글턴 패턴

따봉도치 2020. 9. 15. 16:01

싱글턴 패턴

  • 싱글턴 패턴은 해당 클래스의 인스턴스가 하나만 만들어지고, 어디서든지 그 인스턴스에 접근할 수 있도록 하기 위한 패턴
  • 싱글턴은 제한된 용도로 특수한 상황에서 사용해야함. 남용 x

 

전역변수 사용 시 단점

  • 전역변수에 객체를 대입하면 어플리케이션 시작 시 객체가 생성됨(플랫폼마다 다르지만) 
  • 만약 그 객체가 자원을 많이 차지하는데 아무도 쓰지 않는다면 아무데도 쓸데없는 객체가 되어버림.

고전적인 싱글턴 패턴 구현법

  • 생성자를 private 으로 선언하고, 클래스의 인스턴스를 생성해 리턴해주는 정적 메소드를 만듦
public class Singleton{
    private static Singleton uniqueInstance;
    
    private Singleton() {}
    //생성자를 private으로 선언해 해당 클래스 내부에서만 인스턴스 생성 가능
    
    public static Singleton getInstance(){
    	if(uniqueInstance == null){
        	uniqueInstance = new Singleton();
        }
        return uniqueInstance;
    }
    
	//기타 메소드..
}

//Singleton.getInstance() 이런식으로 사용하면 됨
"게으른 인스턴스 생성(lazy instantiation)"
필요한 상황이 오기 전까지 인스턴스를 생성하지 않고, 요청을 받을 때 생성하는 방법

 

문제점 & 해결

  • 멀티스레딩 환경에선 동기화가 필요
    • public static synchronized Singleton getInstance();
    • -> 속도 문제 발생 / 사실 동기화가 필요한 부분은 인스턴스 변수에 객체를 대입할 때 뿐인데..
  • 더 효율적인 방법은 없을까?
    1. getInstance() 속도가 중요하지 않다면 그냥 두기 (*메소드 동기화 시 성능이 100배정도 저하된다고 함)
    2. 인스턴스를 처음부터 만들어 놓기
    3. DCL(Double-Checking Locking)을 써서 getInstance()에서 동기화 되는 부분을 줄이기 (자바 1.5 전은 사용x)
private volatile static Singleton uniqueInstance;
//volatile 키워드를 사용하면 멀티스레딩 환경에서 변수의 가시성을 보장해줌

public static Singleton getInstance(){
    if(uniqueInstance == null){
       	synchronized (Singleton.class){
       	    //동기화 블록 내에서도 한 번 더 null 체크
       	    if(uniqueInstance == null)
               uniqueInstance = new Singleton();
       	}
    }
    return uniqueInstance;
 }

 

Q&A

  • 모든 메소드와 변수가 static으로 선언된 클래스를 만들어도 되지않나?
    • 복잡한 초기화가 필요없는 경우에만 가능. + 자바에서 정적 초기화를 처리하는 방법 때문에 일이 복잡해질수도
    • 특히 여러 클래스가 얽혀 있는 경우 초기화 순서와 관련된 버그가 발생할 수 있기 때문에 현실적이지 않음
  • 클래스 로더 두 개가 각기 다른 싱글턴의 인스턴스를 가지게 될 수도 있지 않나?
    • 맞음. 따라서 클래스 로더를 여러개 사용하면서 싱글턴을 사용한다면 주의필요. (클래스 로더 직접 지정 등)
  • 전역변수 VS 싱글턴 패턴
    • 전역변수는 객체에 대한 정적 레퍼런스로 '게으른 인스턴스 생성'이 불가하고, 처음부터 끝까지 가지고 있어야함
    • 또한 간단한 객체에 대한 전역 레퍼런스를 자꾸 생성하며 네임스페이스를 지저분하게 만드는 경향이 생김

 

+ 자바 1.2 이전엔 싱글턴에 대한 유일한 레퍼런스가 싱글턴 자체뿐일 경우 가비지 컬렉터에 의해 제거되는 경우가 있었다고 함.

 

연필을 깎으며

page 221

- getInstance() 동기화 : 속도 문제가 발생할 수 있으나 해당 예제에선 신경쓰지 않아도 될 듯

- 인스턴스 미리 초기화 : 어차피 초콜릿 보일러는 항상 필요하기 때문에 정적 초기화도 괜찮을 듯

- DCL 사용 : 특정 JVM 버전에선 작동하지 않기 때문에 x

Comments