Singleton pattern : getInstance()


1. 기본 개념과 형식

public class Singleton {


    private Singleton() {

    }


    private static Singleton sInstance;

    public static Singleton getInstance() {

        if (sInstance == null) {

            sInstance = new Singleton();

        }


        return sInstance;

    }

}

- 어디든 누구든 getInstance() 를 호출하면 항상 같은 Instance를 줘야 한다는 개념이다.

- getter의 명칭 또한 똑같이 쓰기 때문에 구현방식에 대한 포멧같은 느낌



2. 동기화 문제

- 위 코드는 멀티 Thread 상황에서 A Thread가 instance 생성하고 저장하지 않은 시점에 B Thread가 생성하고 저장하고 나갈 수 있는 경우가 생긴다.

  이를 해결하는 방안으로

1) Synchronized를 method에 걸어서 해결

2) static block으로 생성하여 해결

3) Lazy Holder class 이용하여 해결

4) Enum class 로 만들어 해결

  이 있다.



2-1. Synchronized를 method에 걸어서 해결

public class Singleton {


    private Singleton() {

    }


    private static Singleton sInstanceSync;

    public static synchronized Singleton getInstanceSync() {

        if (sInstanceSync == null) {

            sInstanceSync = new Singleton();

        }


        return sInstanceSync;

    }

}

- (차이설명을 위해 명칭을 변경함)

- 말 그대로 synchronized를 걸면 된다.

- 장점: Lazy initialize 가능, Thread safe

- 단점: synchronized의 비용이 비싸다. 즉, 매번 오래걸린다.



2-2. static block으로 생성하여 해결

public class Singleton {


    private Singleton() {

    }


    private static final Singleton STATIC_INSTANCE = new Singleton();

    public static Singleton getInstanceStatic() {

        return STATIC_INSTANCE;

    }

}

- class load되는 시점에 static이 실행되며 객체도 생성된다.

- 장점: Thread safe

- 단점: 필요한 상황에 만들어지는 것은 아니다. 즉, 미리 만들어져 있다.



2-3. Lazy Holder class 이용하여 해결 (좀 더 정확한 명칭은 Initialization-on-demand holder idiom)

public class Singleton {


    private Singleton() {

    }


    private static class LazyHolder {

        public static final Singleton INSTANCE = new Singleton();

    }

    

    public static Singleton getInstanceLazyHolder() {

        return LazyHolder.INSTANCE;

    }

}

- static block과 유사하지만 내부 클래스가 로딩되는 시점에 static이 실행된다.

- 장점: Lazy initialize 가능, Thread safe

- 많이 쓰는 편이라고 한다.



2-4. Enum class 로 만들어 해결

public enum SingletonEnum {

    INSTANCE;

    

    // TODO: your methods

}

- Enum에 메소드를 다는 방식

- 장점: Lazy initialize 가능, Thread safe

- Effective Java 2/E에 나온 방법



3. Singleton instance를 Reflection으로 생성한다면 이 모든 노력은 무용지물

- private 으로 생성자를 막아도 생성이 가능하기 때문




이 내용에 대한 코드는 Github에서도 확인하실 수 있습니다.

https://github.com/ndukwon/Duk_Java_library/tree/master/src/com/duk/lab/java/pattern



Reference

http://jusungpark.tistory.com/16

- https://blog.seotory.com/post/2016/03/java-singleton-pattern

- http://changsuk.me/?p=1433

- https://en.wikipedia.org/wiki/Initialization-on-demand_holder_idiom




+ Recent posts