ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 싱글톤 패턴 *
    기타/디자인패턴 2021. 9. 14. 23:05

    객체가 하나만 필요한 경우

    스레드 풀,

    캐시 대화상자,

    사용자 설정,

    레지스트리 설정 처리 객체,

    로그 기록용 객체,

    프린터나 그래픽카드 같은 디바이스를 위한 디바이스 드라이버 같은 객체 

    연결풀, 스레드풀 관리 

     

    전역변수의 단점

    전역변수에 객체를 대입하면 애플리케이션이 시작될 때 객체가 생성되는데 (*플랫폼에 따라 다름)

    근데 객체가 자원을 많이 차지한다면, 애플리케이션이 끝날 때까지 객체사용을 하지 않을 때 불필요하게 자원을 낭비하게 된다. 

    싱글톤 패턴은 필요할 때만 객체를 생성할 수 있다.

     

    * 어떻게 하면 한 클래스의 인스턴스가 두 개 이상 만들어지지 않도록 할 수 있을까?

    > new Obj(); new 생성자를 사용하지 못하게 한다. => 생성자를 private 으로 선언, 객체를 메서드를 통해 반환한다?

     

    public class ChoclateBoiler {
    
        private static ChoclateBoiler cb;
    
        private ChoclateBoiler(){
            //todo
        }
    
        public static ChoclateBoiler getInstance(){
            if(cb==null){
                cb = new ChoclateBoiler();
            }
            return cb;
        }
        
    }

    * 여기서 생기는 문제 

    스레드 1과 2가 거의 동시에 getInstance 에 접근해 cb=null 조건을 둘 다 통과한다면? => 싱글톤이 깨짐

     

    getInstance 를 synchronized 키워드로 동기화 

    public class ChoclateBoiler {
    
        private static ChoclateBoiler cb;
    
        private ChoclateBoiler(){
            //todo
        }
    
        public static synchronized ChoclateBoiler getInstance(){
            if(cb==null){
                cb = new ChoclateBoiler();
            }
            return cb;
        }
        
    }

    => 하지만 사실 맨 처음 접근할 때를 제외하고 동기화가 필요 없다.

     

    1. getInstance 의 속도가 그리 중요하지 않고, 큰 부담이 없다면 그냥 둬도 된다.

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

    public class ChoclateBoiler {
    
        private static ChoclateBoiler cb = new ChoclateBoiler();
    
        private ChoclateBoiler(){}
    
        public static ChoclateBoiler getInstance(){        
            return cb;
        }    
    }

    3. DCL(Double-Checking-Locking) 을 써 getInstance 의 동기화되는 부분을 줄인다. 

    DCL 을 사용하면 일단 인스턴스가 생성되었는지 확인 후 생성되지 않았을 때만 동기화 할 수 있다.

    이러면 최초에만 동기화하고 그 뒤로 동기화 하지 않는다.

    public class ChoclateBoiler {
    
        private volatile static ChoclateBoiler cb;
    
        private ChoclateBoiler(){}
    
        public static ChoclateBoiler getInstance(){
            if(cb==null){			  // 확인 후 동기화된 블럭으로	
                synchronized (ChoclateBoiler.class){ 
                    if(cb==null){		    //재확인
                        cb = new ChoclateBoiler();
                    }
                }            
            }
            return cb;
        }
        
    }

     

    https://nesoy.github.io/articles/2018-06/Java-volatile

     

    Java volatile이란?

     

    nesoy.github.io

     

     

    싱글톤 사용의 주의사항 

    * 클래스로더와 싱글톤 인스턴스

    클래스 로더마다 서로 다른 네임스페이스를 가지기 때문에 

    클래스 로더가 2개 이상이라면 , 같은 클래스를 각 클래스마다 로딩해 싱글톤으로 작성한 클래스의 인스턴스가 클래스 로더의 개수만큼 생성될 수 있다! 

    따라서 클래스 로더를 여러개 사용 시 싱글톤 사용을 주의해야한다. 직접 클래스 로더를 지정해서 이 문제를 피할 수도 있다. 

     

    https://javacan.tistory.com/entry/1

     

    클래스로더 1, 동적인 클래스 로딩과 클래스로더

    동적인 클래스 로딩 자바는 동적으로 클래스를 읽어온다. 즉, 런타임에 모든 코드가 JVM에 링크된다. 모든 클래스는 그 클래스가 참조되는 순간에 동적으로 JVM에 링크되며, 메모리에 로딩된다.

    javacan.tistory.com

    *싱글톤은 제한된 용도로 특수한 상황에서 만드는 것이 바람직하다. 애플리케이션에서 싱글톤을 만힝 사용한다면 전반적인 디자인에 대한 고려가 필요할 수 있다.

     

     

    반응형

    '기타 > 디자인패턴' 카테고리의 다른 글

    컴파운드 패턴  (0) 2021.09.23
    행위패턴 > 템플릿 메서드 *  (0) 2021.02.12
    행위패턴 > 상태(State) *  (0) 2021.02.12
    행위패턴 > 옵저버 *  (0) 2021.02.12
    행위패턴 > 이터레이터 *  (0) 2021.02.11
Designed by Tistory.