Singleton이란?
프로그램상에서 동일한 인스턴스를 만들어 내는 것이 아닌 동일 인스턴스를 사용하게 하는 것
동일한 컨넥션 객체를 만든다던지, 하나만 사용되어야 하는 객체를 만들때 사용한다.
매우 자주 쓰이는 패턴중 하나이다.
Singleton Pattern들
Eager Initialization
가장 기본적인 Singleton Pattern.
먼저 클래스 내에 전역변수로 instance 변수를 생성하고 private static을 사용하여 인스턴스화에 상관없이 접근이 가능하면서 동시에 private 접근제한자를 사용하여 class.instance로 바로 접근 할 수 없도록 한다. 또 생성자에도 private 접근제한자를 붙여서 다른 클래스에서 new 방식의 새로운 인스턴스를 생성하는 것을 방지한다.
오로지 전역변수가 포함된 클래스 내에 getInstance() 같이 메서드를 만들어 사용하여 인스턴스에 접근하도록 한다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | package SingleTonExample; public class EagerInitialization { // private static으로 전역변수 선언 private static EagerInitialization instance = new EagerInitialization(); // private 생성자 private EagerInitialization() {} // 인스턴스 리턴 Method public static EagerInitialization getInstance() { return instance; } }
|
static 전역변수로 생성되었으므로 클래스가 로딩될 때 객체가 생성되므로 Thread-Safe하다.
하지만 객체의 사용유무와 상관없이 클래스가 로딩되면 항상 객체가 생성되고, 메모리를 사용하므로 객체 생성비용이 적은 경우나 항상 쓰는 객체일 때 쓴다.
Lazy Initialization
인스턴스 생성 시점이 인스턴스가 사용되는 시점이다. 따라서 객체 사용전까지는 메모리를 점유하지 않는다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | package SingleTonExample; public class LazyInitialization { // private static으로 전역변수 선언 private static LazyInitialization instance; // private 생성자 private LazyInitialization(){} // 인스턴스 리턴 Method // 인스턴스가 null일 때만 생성 public static LazyInitialization getInstance(){ if (instance == null ){ instance = new LazyInitialization(); } return instance; } } |
객체가 필요할 때 인스턴스를 얻을 수 있다. Eager Initialization 단점 보완.
하지만 multi-thread환경이라면 인스턴스가 두개 혹은 여러개 생성될 여지가 있다. Singleton 아니게 될 수 있다.
Thread sage Lazy Initialization
Lazy Initialization 단점을 보완하기위해 synchronized 를 사용한 방식.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | package SingleTonExample; public class ThreadSafeLazyInitialization{ // private static으로 전역변수 선언 private static ThreadSafeLazyInitializationinstance; // private 생성자 private ThreadSafeLazyInitialization(){} // 인스턴스 리턴 Method // synchronized 사용 public static synchronized ThreadSafeLazyInitializationgetInstance(){ if (instance == null ){ instance = new ThreadSafeLazyInitialization(); } return instance; } } |
thread-safe하지만 synchronized를 쓰게 되면 내부적으로 multi-thread에 안전한 환경을 만들기 때문에 많은 비용이 발생한다. 따라서 성능저하가 일어날 수 있다.
Thread sage Lazy Initialization + Double-checked locking
위의 방식에서 성능저하를 방지하기위해 만든 방법.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | package SingleTonExample; public class ThreadSafeLazyInitialization { // private static으로 전역변수 선언 private static ThreadSafeLazyInitialization instance; // private 생성자 private ThreadSafeLazyInitialization(){} // 인스턴스 리턴 Method // instance생성을 두번 체크하여 성능저하 보완 public static ThreadSafeLazyInitialization getInstance(){ if (instance == null ){ synchronized (ThreadSafeLazyInitialization. class ) { if (instance == null ) instance = new ThreadSafeLazyInitialization(); } } return instance; } } |
Initialization on demand holder idiom
클래스 안에 Holder클래스를 만들어 Lazy initialization 방식을 가져가면서 thread 동기화 문제를 해결하는 방식이다. 중첩클래스인 Holder는 GetInstance Method가 호출되기 전까지는 참조되지 않으며 최초로 호출될 때 객체를 생성한다. static을 이용하여 한 번만 호출되게하고 final을 써서 다시 값이 할당되지 않게 한다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | package SingleTonExample; public class InitializationOnDemandHolderIdiom { // private 생성자 private InitializationOnDemandHolderIdiom(){} // private static Holder 클래스 private static class SingleTonHolder{ private static final InitializationOnDemandHolderIdiom instance = new InitializationOnDemandHolderIdiom(); } // 인스턴스 리턴 Method // Holder클래스에서 생성한 객체를 불러온다. public static InitializationOnDemandHolderIdiom getInstance(){ return SingleTonHolder.instance; } } |
Singleton Pattern중 가장 많이 사용한다고 한다.
Initialization on demand holder idiom
이번에는 enum의 특징을 이용한 방법이다. enum type들은 프로그램 내에서 한 번 초기화되는 점을 이용함.
1 2 3 4 5 6 7 8 9 10 | package SingleTonExample; public enum EnumSingleTon { INSTANCE; static String test = ""; public static EnumInitialization getInstance() { test = "test"; return INSTANCE; } |
Enum이 생성될 때 multi thread로부터 안전하다. (추가된 Method들은 safed 하지 않을 수 있다.)
단 한번의 인스턴스 보장하고 사용이 간편하다.
Reference
http://limkydev.tistory.com/67
https://blog.seotory.com/post/2016/03/java-singleton-pattern
'프로그래밍 > 디자인 패턴(프로그래밍)' 카테고리의 다른 글
[Design Pattern]Prototype Pattern이란? (0) | 2019.01.17 |
---|---|
[Design Pattern]Builder Pattern이란? (0) | 2019.01.17 |
[Design Pattern]Abstract Factory Pattern이란? (0) | 2019.01.17 |
[Design Pattern]Factory Method Pattern이란? (0) | 2019.01.17 |
[프로그래밍]Design Pattern Outline, 디자인 패턴이란? (0) | 2019.01.16 |
댓글