Singleton Pattern

1445664805_web-code

1. 개요

개발을 하다 보면 수많은 인스턴스를 new하여 생성 한다. 예를 들어 String 문자열 을 1000개 만들면 1000개의 인스턴스가 생성되어 메모리에 자리 잡게 된다. 여러개의 변수들을 필요로 하는 경우엔 이렇게 인스턴스를 그때마다 생성하여 사용 하는게 익숙해져 있을 것 이다.

하지만, 클래스의 인스턴스가 단 하나만 필요한 경우가 있다. 프로세스 상에서 단 1개의 클래스 인스턴스가 new로 생성 되어 메모리에 자리잡고 어떤 다른 객체에서 전역 변수를 호출 하 듯이 getter/setter 등으로 접근하는 방식 인 것 이다.

이러한 패턴을 자주 사용 하는 예로는 게임이 있다. 게임에서는 수많은 설정 들 이 있을 것이다. 눈으로 보여지는 그래픽 옵션이나 사운드, 컨트롤 옵션등 이다. 보통 이런 옵션등은 파일들로 저장하여 관리 하지만 내부적으로 가볍게 다루어지는 옵션들은 이러한 싱글턴 패턴으로 구현 되어 단 하나의 인스턴스만 가지고 현재 포커스를 받은 객체에서  접근하여 어떠한 옵션들에 대한 세팅을 바꾸는 것 이다.

간단하게 설명해 보자. 게임에서 내가 effect 불륨을 1 증가 시켰다. 이 1증 가는 사실 이미 만들어진 싱글턴 패턴의 인스턴스를 잠시 가져온 다음에 setter메소드를 이용하여 effect 불륨을 1 증가시키는 메소드를 콜 한다. 이 인스턴스 내 에서는 이 기능을 수행 하고 잠시 그 값을 가지고 있다가 사용자가 설정 화면의 ‘확인’버튼을 누르는 순간 싱글톤에서 관리 된 변경된 정보들을 옵션 파일에 저장 하게 될 것이다.

메모리상에 단 한개만 존재함으로 인한 장점과 단점은 있다. 메모리상에 단 한개만 존재 하기때문에 개발자 입장에선 관리하기 편하다. 인스턴스가 프로그램 상에 단 한개만 존재한다는 것은 개발자 입장에서 생각하기 편하게 해준다. 또한 사용성도 무궁무진 하고 편하다.

하지만 단점이 존재 한다면, 여러 객체에서 접근 할 수 있다는 점 이다. 현재 포커스를 받은 객체(사용중인)에서 이 싱글톤 인스턴스에 접근하여 뭔가를 set하는데 다른 객체에서 이미 어떤값을 set했는지 현재 어떤 값인지 확실하지 않을 수도 있다.  그리고 멀티 스레드 환경에서의 동기화 문제나 원자성 문제 또한 가지고 있을 것 이다.

Singletone 패턴은 매우 자주 사용되는 패턴 들 중에 하나 이다. 그만큼 사용성이 좋고 편리하다는 것 이다. 이 패턴에서는 개발자가 주의를 기울여서 1개 인스턴스만 생성 하는 것 이 아니라, 지정한 클래스의 인스턴스가 ‘절대적으로’ 1개 만 존재하는 것을 ‘보증’ 하고, 인스턴스가 1개만 존재함을 프로그램 상에서 표현하고 싶을때 이러한 패턴을 사용 한다.

 

2. 예제 및 설명

싱글톤 패턴의 구현은 여러가지 방법들이 있다. 그 중에서도 주목 해야 할 점은, private로 선언된 생성자생성된 인스턴스를 가져와서 사용 할 수 있는 getInstance() 메소드 이다. 이러한 주목 점은 모든 구현 방식에서 동일 하다.

 

Eager initialization

인스턴스를 필요할때 생성하는 방법이 아닌 처음부터 만들어 버리는 방법이다. 클래스가 로딩 될 때 JVM에서 유일한 인스턴스를 생성해주는 방법이다.

간편하고 사용하기 쉽다. 작은 클래스를 다루는데 적합 하다. 하지만, 이 클래스에서 다루는 데이터나 하는 작업-init() 등이 많아지면 부담스러워 질 수도 있다.  JVM에서 인스턴스화 하는데 있어 오류 핸들링을 할 수 없다.

private 메소드인 생성자는 외부에서 이 생성자를 통해서 new 할 수 없다. 생성된 인스턴스를 가져오기 위해서는 getInstance() 메소드를 통해서 생성된 인스턴스를 가져 올 수 있다. 몰론 이 클래스에서 초기화 과정들 중 작업이 있을 수 있기 때문에 private로 선언된 생성자 내부에서 init()메소드를 호출 하여 초기화 작업을 할 수 있다.

 

Static block initialization

static 블럭{} 을 이용하여 내부에서 오류 핸들링 처리를 포함한 생성 방식이다. 클래스가 로드 될때 static블럭 때문에 한번만 실행하게 되면서 오류를 핸들링 할 수 있게 된 것이다.

하지만 여전히 위의 초기화 방법과 동일하게 미리 인스턴스를 만들어버리기 때문에, 클래스 로드 시의 부담은 동일 하다.

 

Lazy initialization

이 방식은 클래스가 로드 할 때 인스턴스를 생성하는게 아닌, getInstance()를 이용하여 인스턴스를 얻으려고 시도 할때 인스턴스가 생성되지 않았을 경우에만 생성하고 그 다음 반환하는 형태 이다.

인스턴스는 static이긴 하지만 new 를 통해서 생성되고 있지 않다가 getInstance()를 호출 할 경우 인스턴스가 생성되어있지 않을때에 new 해서 반환하기 때문에 메모리의 부담은 덜하게 된다.

하지만 아직까지 문제가 남아 있다. 만약 프로그램 내부에서 멀티 스레딩 처리가 되고 있을 경우 이다. 위 구현 형태는 이러한 멀티 스레드 환경에서 안전하지 않다. 두개의 스레드가 동시에 접근하여 getInstance()를 하게 된 다면 동시에 2개 이상의 인스턴스가 메모리에 생성 될 수 있다. 이렇게 되면 Singletone pattern을 사용하는 의미가 없다.

 

Thread safe initialization

동기화(synchronized)를 getInstance()메소드에 사용하여 멀티 스레드 문제를 해결한 방법 이다. 이렇게 구현하게 되면 스레드들의 동시 접근으로 인한 인스턴스의 다중 생성은 막을 수 있다. 하지만 여러개의 스레드 들이 getInstance()에 접근하게 되면 한개의 스레드가 getInstance()를 선점 하고 있을 경우 다른 스레드 들은 기다려야 함으로서 결국 프로그램 전체에 대해 성능 저하가 생길 것 이다.

 

Initialization on demand holder idiom

미국 메릴랜드 대학의 Bill pugh가 기존의 싱글톤 구현에 문제점을 해갈 한 새로운 구현 방법 이다. 이것은 jvm 클래스 로더와 class의 로더 시점을 이용하여 inner class를 생성하여 스레드간 동기화 문제를 해결 한다.

몰론 getInstance()를 통해서 인스턴스를 생성 하기 때문에 lazy initialization이 가능하며 모든 java버전에서 사용 가능 하다. 만약 Singletone패턴을 사용한다면 위와 같은 패턴을 사용한다고 생각 하면 된다.

 

enum initialization

joshu bloch가 제시한 enum을 이용한 방식의 싱글톤 이다.

INSTANCE가 생성될 때 멀티 스레딩 환경으로부터 안전 하며 단 한번의 인스턴스 생성을 보장 한다. 또한 enum은 자바 프로그램의 전역에서 접근이 가능 하기 때문에 싱글톤 처럼 사용 할 수 있다.

 

3. 정리 해 봅시다

싱글톤패턴은 매우 다양한 곳에서 사용 된다. java 내부의 구현에서 많이 사용되며 여러 API에서도 두루 사용될 정도로 사용성이 무궁무진한 패턴이라고 할 수 있다. 실제로 개발을 하다 보면 프로그램 내에서 단 한개의 인스턴스만 가지고 그 인스턴스에 언제던지 접근하여 데이터들을 get/set할 수 있다는 점은 매우 유용하다.

하지만  싱글톤 패턴을 사용함에 있어 주의할점이 존재 한다. 아무래도 static하게 전역으로 만들어지는 인스턴스이다 보니 많은것을 담기에는 부담 스럽다. 또한 여러 객체에서 접근해서 get/set  할 수 있다는 것은 모든 접근을 제어해야 하며 프로그램이 커지고 소스의 양이 많아지면 그 또한 부담 스러울 것 이다. 또한 java의 reflection을 이용해서 인스턴스를 추가로 생성하는 방법도 있다고 한다.

개인적인 생각으로서 싱글톤 패턴은 최소화 해서 사용하는게 좋다고 생각 된다. 전역으로 데이터를 다루는 것은 아무래도 위험스럽다. 그것은 여러 객체에서 접근 가능한 점이 있으며 개발자가 아무리 관리를 한다고 해도 부족한 점은 생길 수 밖에 없으며 이것은 치명적인 오류의 가능성을 내포 하고 있다는 것 이다.

그래서 최소한의 사용에서만 싱글톤을 사용하며 데이터의 get/set을 최소화 하는것이 좋다고 생각 된다. 꼭 필요한 이것 아니면 어쩔수 없는 환경에서 최소한의 메모리를 사용하면서 구현하는게 좋다고 생각 된다.

 

 

참고 : Java언어로 배우는 디자인 패턴 입문

You may also like

댓글 남기기

이메일은 공개되지 않습니다. 필수 입력창은 * 로 표시되어 있습니다.