티스토리 뷰

728x90
반응형

싱글턴 패턴

클래스 인스턴스가 하나만 만들어지도록 하고, 그 인스턴스에 대한 전역 접근을 제공
  • 전역 변수에 객체를 대입하면 애플리케이션이 시작될 때 객체가 생성
    • 한 번도 쓰지 않더라도 자원을 차지
  • 싱글턴 패턴은 필요할 때만 객체 생성

고전적인 싱글턴 패턴

public class Singleton {
	private static Singleton uniqueInstance;	//유일한 인스턴스를 저장하는 정적 변수
    
    private Singleton() {}	//외부에서 생성 불가능
    
    public static Singleton getInstance() {	//유일한 인스턴스를 반환하는 정적 메소드
    	if (uniqueInstance == null) {
        	uniqueInstance = new Singleton();	//게이른 인스턴스 생성
        }
        return uniqueInstance;
    }
}

멀티스레딩 문제 해결 방법

public class Singleton {
	private static Singleton uniqueInstance;
    
    private Singleton() {}
    
    public static synchronized Singleton getInstance() {	//동기화 추가, 속도 문제 발생
    	if (uniqueInstance == null) {
        	uniqueInstance = new Singleton();
        }
        return uniqueInstance;
    }
}

애플리케이션이 시작하자마자 인스턴스 생성

public class Singleton {
	private static Singleton uniqueInstance = new Singleton();	//정적 초기화 부분에서 생성
    
    private Singleton() {}
    
    public static Singleton getInstance() {
    	return uniqueInstance;	//인스턴스가 이미 있으니까 그냥 리턴
    }
}

DCL (Double-Checking Locking)

public class Singleton {
	private volatile static Singleton uniqueInstance;	//volatile 키워드 jdk 1.5 이상
    
    private Singleton() {}
    
    public static Singleton getInstance() {
    	if (uniqueInstance == null) {	//인스턴스가 없을 때 동기화 블럭 진입
        	synchronized (Singleton.class) {
            	if (uniqueInstance == null) {	//동기화 블럭 내에서 다시 한번 체크
            		uniqueInstance = new Singleton();
                }
            }
        }
        return uniqueInstance;
    }
}

volatile 키워드를 사용하는 경우 instance는 CPU캐시에서 변수를 참조하지 않고 메인 메모리에서 변수를 참조한다.

그래서 위에서 초기에 제시된 DCL singleton패턴에서 reorder문제가 발생하지 않는다.

Lazy-Holder

public class Singleton {
	private Singleton(){}

	public static Singleton getInstance() {
		return LazyHolder.INSTANCE;
	}

	private static class LazyHolder {
		private static final Singleton INSTANCE = new Singleton();
	}
}

LazyHolder 클래스의 변수가 없기 때문에 Singleton 클래스 로딩 시 LazyHolder 클래스를 초기화하지 않는다. Singleton 클래스의 getInstance() 메서드에서 LazyHolder.INSTANCE를 참조하는 순간 Class가 로딩되며 초기화가 진행된다. Class를 로딩하고 초기화하는 시점은 thread-safe를 보장하기 때문에 volatile이나 synchronized 같은 키워드가 없어도 thread-safe 하면서 성능도 보장하는 아주 훌륭한 방법이다.

728x90
반응형
반응형
300x250