ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [디자인 패턴] 싱글톤 패턴 타파 및 대응 방안
    JAVA/GoF 디자인 패턴 2024. 4. 8. 23:41
    728x90
    728x90

    1.static 메서드와 private 생성자 방식

    자바에서 싱글톤 패턴을 처음 배우는 방식이다.

    public class Settings {
    
        private Settings() {}
    
        private static Settings instance = null;
    
        public static Settings getInstance() {
            if(instance == null) {
                instance = new Settings();
            }
            return instance;
        }
    }

    하지만 이 방법으로 싱글톤을 설계하게되면 쓰레드 safe하지 않게 된다.
    예를 들어 쓰레드 A와 B가 거의 동시에 Settings의 getInstance()에 접근했다고 생각해보자.
    A가 처음 getInstance()를 접근했을 때 instance는 null이기 때문에 새롭게 Settings()를 생성하려고 하지만,
    동시에 B도 생성하려고 하기 때문에 싱글톤이 깨지게 되는 것이다.

    그럼 멀티 쓰레드 환경에 안전하게 싱글톤을 사용하려면 어떻게 해야하는 걸까?

     

    synchronized 키워드 또는 더블체킹을 사용하는 것이다.

        public static synchronized Settings getInstance() {
            if(instance == null) {
                instance = new Settings();
            }
            return instance;
        }

     

    메서드 전체에 lock을 거는데 비용이 걱정된다면 더블 체킹을 사용해보자.

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

    instance가 없을 때만 synchronized가 적용되기 때문에 이전 방법보다는 비용이 덜 걱정될 것이다.
    이 경우에는 instance에 volatile 키워드가 필요하다.

     

     


    1번으로 싱글톤을 적용해보면 클래스 로딩과 동시에 instance가 생성된다는 단점이 있다.
    이를 해결하기 위해 static inner class로 싱글톤을 설계해보자.

     

    2. static inner class 방식

    public class Settings {
    
        private Settings() {}
    
        private static class SettingsHolder {
            private static final Settings INSTANCE = new Settings();
        }
    
        public static Settings getInstance() {
            return SettingsHolder.INSTANCE;
        }
    }

    SettingsHolder라는 static inner class를 생성해서
    Settings의 getInstance가 호출되었을 때 instance를 생성하게 할 수 있다.

     

     

    그렇다면 2번의 방법은 싱글톤에 만능인 것인가?
    결론을 말하자면 만능인 것은 아니다.
    자바의 Reflection을 사용하여 Settings를 생성하게 되면 다른 instance를 생성할 수 있고, 싱글톤이 깨지게 된다.
    코드로 살펴보자.

    Settings settings = Settings.getInstance();
    
    Constructor<Settings> constructor = Settings.class.getDeclaredConstructor();
    constructor.setAccessible(true);
    Settings settings1 = constructor.newInstance();

    이렇게 생성된 settings1은 settings 와 다른 객체이다.

     

     


    자바의 Reflection을 막으려면??

    3. Enum 으로 싱글톤 생성

    Enum으로 상수를 생성해보았지만 싱글톤 객체를 생성하는건 이번 공부를 통해 처음 알았다.
    코드 또한 간단하다.

    public enum Settings {
    	INSTANCE;
    }

     

    Enum은 Reflection을 막아뒀기 때문에 싱글톤을 유지할 수 있게 된다.
    하지만 static 메서드의 단점과 동일하게 로딩과 동시에 instance가 생성된다, 상속이 안된다는 단점이 있다.

     

     

     

    결론은?

    강의에서도 주로 쓰이는건 2번과 3번이라고 하셨다.
    메모리에 크게 부담이 되지 않고, 상속을 안해도 된다면 enum을 사용하는 것도 좋고,
    그 외에는 static inner class를 사용해도 좋으니 상황에 맞게 사용하면 될 것이다.

     

     

     

    [출처] 코딩으로 학습하는 GoF의 디자인 패턴 - 백기선

    728x90
    728x90
Designed by Tistory.