난 지금까지 싱글톤이 멀티스레드 환경에서 위험한건지 몰랐는데
요새 공부하다보니까 찰나에 순간에 인스턴스가 2개이상 생성되어버리는 경우가 있다고 하더군.
검색을 좀 해보니까 가장 괜찮은 방법은 enum 을 이용해서 싱글톤 클래스를 만드는건데
Q. 이게 가장 최선의 방법인지 궁금하네.
그리고 enum 이라는게 그냥 열거형 타입으로 타입정의할때 쓰는건줄 알았는데
enum에서 정의한 타입의 인스턴스를 단 하나만 생성하도록 관리까지해주는 신박한놈인줄은 몰랐당.
어쨋든 싱글톤 만들때 다들 어떻게 만들어?
난 여태까지 최초로 요청이왔을때 인스턴스 생성해주는 방법으로 했었는데
이제 enum으로 만들어서 쓰려고.
그냥 스레드가 이미 생성되었는지 체크하는 변수에 lock을 걸면 되잖아. enum으로는 해결이 안될 거 같은데?
lock걸면 오버헤드가 너무커 enum으로는 왜 해결이 안된다고 생각하는데?
오버헤드가 크다는 근거는? 그냥 lock을 걸면 당연히 바보짓이고, DCL(Double-checked locking) 패턴으로 짜는 게 일반적. Java에서는 이렇게 짜면 안된다 알려져 있지만 그것도 옛날 말임. volatile 키워드로 짜면 안전해.
http://en.wikipedia.org/wiki/Double-checked_locking
중간 부분의 volatile 들어있는 코드를 참고해라.
DCL로 짜는게 일반적이야? 그 부분도 안알아본건 아닌데 DCL로 할경우에 리플렉션이나 직렬화에 대해서 처리를 해줘야하기때문에 enum으로 싱글톤을 구현하는게 가장 편리하다고 생각한거거든 enum으로는 해결이 안된다는 이유를 좀 들을수 있을까?
싱글톤으로 인스턴스를 하나만 생성하고 싶으면, 1) 대상 클래스 A의 가시성을 default로 한정함. public을 뗀다는 말이지.. 그리고나서 임의의 패키지에 담으면 패키지 바깥에서는 클래스 A의 생성자를 호출할 수 없고. 2) 클래스 A와 동일한 패키지 안에 정의된 또다른 클래스 B가 클래스 A의 생성자를 딱 한 번만 호출하도록 프로그래밍 함.
3) 클래스 B는 클래스 A의 생성자를 한 번 호출해서 얻어낸 인스턴스를 내부에 참조 보관함으로써 사실상의 싱글톤 효과를 보게 됨. 이렇게 될 경우 다른 모듈(컴포넌트)에서 이 인스턴스를 가져다 써야할 때 클래스 A는 가시성이 default이기 때문에 컴파일 에러가 발생하겠지 4) 그래서 인터페이스 IA 를 정의해서 클래스 A가 IA를 구현하게 함 5) 다른 모듈은 클래스 A를 IA 타입으로 보게됨.
과거에는 생성자를 private으로 놓고, 내부에 static 변수를 만들고, 또 이 변수에 인스턴스를 할당하고 반환해주는 static newInstance() 같은 메소드를 만들어서 싱글톤을 구현했는데.. 이런 경우 구현이 경직되어서 향후에 변경 사항이 발생하면 아주 곤란한 상황이 자주 발생하기때문에... 설계를 통해서 사실상의 싱글통 효과를 보게 하는 쪽을 선호함.
요약하면.... 스레드들이 마구 경쟁하는 상황에서 특정 클래스의 인스턴스가 딱 하나만 생성되도록 하려고 락을 걸고 해제하는 번거롭고 난잡한 일을 하지 말고... 스레드들을 start 시키기 전에 미리 인스턴스를 하나만 만들어두고 그 클래스에 직접 접근하지 못하게 제한하면 이게 사실상 싱글톤 아니냐... 뭐 이런 것이지...