티스토리 뷰

반응형

싱글턴 패턴

 싱글턴 패턴(Singleton Pattern)은 클래스 인스턴스를 단 하나만 만들고, 이 하나의 인스턴스로만 클래스에 대한 접근을 허용하는 패턴입니다.
 


 

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

public class Singleton {
    // 하나뿐인 인스턴스를 저장하는 정적 변수
    private static Singleton uniqueInstance;
    
    // 기타 인스턴스 변수
    
    // 생성자를 private으로 설정
    private Singleton() {}
    
    // 클래스의 인스턴스를 만들어 리턴하는 getInstance() 메소드
    public static Singleton getInstance() {
    	if (uniqueInstance == null) {
        	uniqueInstance = new Singleton();
        }
        return uniqueInstance;
    }
    
    // 기타 메소드
}

 
 

멀티스레딩 문제

 멀티 스레드 환경에서  고전적인 방법으로 싱글턴 패턴을 구현하면 여러 스레드가 getInstance() 메소드를 동시에 호출하면서 여러 객체가 생성되는 문제가 발생합니다. 멀티스레딩을 유지하면서 싱글턴 패턴을 구현하기 위해서는 다음과 같은 해결법들이 있습니다.
 

1. 'synchronized' 키워드를 사용한다.

public class Singleton {
    // 하나뿐인 인스턴스를 저장하는 정적 변수
    private static Singleton uniqueInstance;
    
    // 기타 인스턴스 변수
    
    private Singleton() {}
    
    public static synchronized Singleton getInstance() {
    	if (uniqueInstance == null) {
        	uniqueInstance = new Singleton();
        }
        return uniqueInstance;
    }
    
    // 기타 메소드
}

 이 경우 한 스레드가 getInstance() 메소드 사용을 끝내기 전까지 다른 스레드는 기다려야하면서 2개의 스레드가 이 메소드를 동시에 실행하는 일은 일어나지 않습니다. 하지만 getInstance() 메소드를 동기화하면 성능이 100배 정도 저하됩니다.
 
 
 

2. 인스턴스를 처음부터 만들어 둔다.

public class Singleton {
    private static Singleton uniqueInstance = new Singleton();
    
    private Singleton() {}
    
    public static Singleton getInstance() {
    	return uniqueInstance;
    }
}

 정적 초기화 부분에서 미리 인스턴스를 생성하면 스레드를 써도 문제가 되지 않습니다.
 
 
 
 

3. 'DCL'을 써서 getInstance()에서 동기화되는 부분을 줄인다.
 

 DCL(Double-Checked Locking)을 사용하면 인스턴스가 생성되어 있는지 확인한 다음 생성되지 않았을 때만 동기화를 할 수 있습니다. 'volatile' 키워드를 사용하면 멀티스레딩을 쓰더라도 싱글톤 인스턴스로 초기화되는 과정이 올바르게 진행됩니다.
 

public class Singleton {
    private volatile static Singleton uniqueInstance;
    
    private Singleton() {}
    
    public static Singleton getInstance() {
    	if (uniqueInstance == null) {
        	synchronized (Singleton.class) {
            	if (uniqueInstance == null) {
                	uniqueInstance = new Singleton();
                }
            }
        }
        return uniqueInstance;
    }
}

 
 그러나 이 3가지 해결법들은 모두 앞에서 언급했던 동기화 문제와 더불어 클래스 로딩 문제, 리플렉션, 직렬화/역직렬화와 같은 많은 문제점들이 존재합니다.

➡️ 이 문제점들은 enum을 이용해 싱글턴을 생성하는 방식으로 쉽게 해결할 수 있답니다.
 


 

enum으로 싱글턴 구현하기

public enum ChocolateBoiler {
    UNIQUE_INSTANCE(true, false);
    
    private boolean empty;
    private boolean boiled;
    
    private ChocolateBoiler () {
    	...
    }
    
    public void fill() {...}
    
    public void drain() {...}
    
    public void boil() {...}
    
    ...
}

 
 
참조:

 

헤드 퍼스트 디자인 패턴(개정판)

유지관리가 편리한 객체지향 소프트웨어 만들기! “『헤드 퍼스트 디자인 패턴(개정판)』 한 권이면 충분합니다!”

m.hanbit.co.kr

 

반응형