-
싱글턴 패턴컴퓨터/객체지향_디자인패턴 2019. 9. 3. 23:24
- 싱글턴이란?
특정 클래스에 대해서 객체 인스턴스가 하나만, 필요할 때만! 만들어질 수 있도록 해주는 패턴
어디서든지 그 인스턴스에 접근할 수 있도록 하기 위한 패턴
Singleton.getInstance() 와 같은 형태 - 어디서든 무조건 같은 인스턴스가 리턴
제한된 용도로 특수한 상황에서 사용!
- 사용예
스레드 풀, 캐시, 대화상자, 사용자 설정, 레지스트리 설정을 처리하는 객체, 로그 기록용 객체, 프린터나 그래픽 카드 같은 디바이스를 위한 디바이스 드라이버
-> 인스턴스를 두 개 이상 만들게 되면 프로그램이 이상하게 돌아간다든가 자원을 불필요하게 잡아먹는 경우, 결과에 일관성이 없어지는 경우
- 필요성
1) 전역변수의 단점
: 애플리케이션이 시작될 때 객체 생성, 그 객체가 자원을 많이 차지하는데 사용하지 않는다면 자원만 잡아먹는다.
싱클턴은 필요할 때만 객체를 만들 수 있다. (lazy instantiation)
- 어떻게 하면 한 클래스의 인스턴스가 두 개 이상 만들어지지 않도록 할 수 있을까?
정적 클래스 변수와 메소드, 접근 변경자를 잘 다룰 줄 알아야
[고전적인 싱글턴 패턴 구현법]
public class Singleton { // Singleton 클래스의 유일한 인스턴스를 저장하기 위한 정적 변수 private static Singleton uniqueInstance; // 기타 인스턴스 변수 // 생성자를 private으로 선언했기 때문에 singleton에서만 클래스의 인스턴스를 만들 수 있다. private Singleton() {} // class의 instance를 만들어서 반환해준다 public static synchronized Singleton getInstance() { if (uniqueInstance == null) { uniqueInstance = new Singleton(); } return uniqueInstance; } // 기타 메서드 }
생성자가 private으로 구현되어 있다.
클래스에 인스턴스를 달라고 요청해야 한다.
- 특징
1) 전역 변수와 마찬가지로 객체 인스턴스를 어디서든지 접근할 수 있다.
그러나 전역 변수는 객체에 대한 정적 레퍼런스이고 레퍼런스를 자꾸 만들게 되면서 네임스페이스를 지저분하게 만들 수 있다.
2) 클래스에서 인스턴스 관리
3) 정적 변수를 바탕으로 구현 -> 서브 클래스를 만들면 모든 서브클래스들이 똑같은 인스턴스 변수를 공유한다.
따라서 베이스 클래스에서 레지스트리 같은 걸 구현해야 한다
- 주의 1: 클래스 로더가 여러 개 있으면 싱글턴이 제대로 작동하지 않고 여러 개의 인스턴스가 생길 수 있다.
- 주의 2: 멀티스레딩 문제 : 스레드가 추가되면 객체가 여러 개 생성될 수 있다.
how to solve?
1) synchronized로 동기화시킨다
public static synchronized 클래스명 메서드명() {}
한 스레드가 메소드 사용을 끝내기 전까지 다른 스레드는 기다려야 한다.
두 스레드가 해당 메서드를 동시에 실행하는 일이 없다.
이 방법의 단점 : 일단 uniqueInstance 변수에 인스턴스가 대입되면 동기화된 상태를 유지할 필요가 없다.
동기화하면 성능이 100배 정도 저하된다.
2) 인스턴스를 처음부터 만들어버리기
public class Singleton { // 정적 초기화부분(static initializer)에서 인스턴스를 생성한다. private static Singleton uniqueInstance = new Singleton(); private Singleton() {} public static Singleton getInstance() { return uniqueInstance; } }
클래스가 로딩될 때 JVM에서 싱글턴의 유일한 인스턴스를 생성해준다.
3) DCL(Double-checking Locking)을 써서 getInstance()에서 동기화되는 부분을 줄인다.
인스턴스가 생성되어 있는지 확인하고 생성되어 있지 않았을 때만 동기화할 수 있다.
처음에만 동기화 가능
public class Singleton { // volatile : 멀티스레딩을 쓰더라도 uniqueInstance 변수가 Singleton 인스턴스로 // 올바른 과정으로 초기화할 수 있어 private volatile static Singleton uniqueInstance; private Singleton () {} public static Singleton getInstance() { if (uniqueInstance == null) { synchronized (Singleton.class) { if (uniqueInstance == null) { uniqueInstance = new Singleton(); } } } return uniqueInstance; } }
- 주의 3 : 1.2 버전보다 전에 나온 JVM을 사용하는 경우에는 가비지 컬렉터 관련 버그 때문에 싱글턴 레지스트리를 사용해야 할 수도 있다.
출처 : headfirst design pattern
'컴퓨터 > 객체지향_디자인패턴' 카테고리의 다른 글
디자인 원칙 : OCP (0) 2019.09.07 옵저버 패턴 (0) 2019.09.07 데이터를 화면에 표시하는 방법 : MVC 패턴 (0) 2019.09.07 플라이웨이트 패턴 (0) 2019.09.03