본문 바로가기

💻 개발IT/Design Patterns

4. Creational 패턴 - Singleton Pattern

Singleton Pattern

class의 단 하나의 instance를 만들고자하는 패턴

 

구현

new 연산자를 사용하지 않고(private constructor) 함수(static method. 외부에서 Instance 없이 접근할 수 있도록)를 통해 인스턴스 생성한다.

  ※ constructor를 안 만들면 기본적으로 public constructor가 생성된다.

getInstance함수를 통해서 내부의 uniqueInstance를 리턴해준다.

이 때, 밖에서 변경하지 못하도록 uniqueInstance는 private로 변경하고, static getInstance()에서 사용해야하기 때문에 static variable로 만들어준다. 

 

그러나 이 코드는 아래와 같은 문제가 있다.

 

예시)

 

Multi-thread에서 Singleton Pattern

위 코드로 진행하면 Multi-thread에서 오류(Instance가 최대 Thread 수만큼 생성)가 날 수 있다. 

 

해결 방안 1

getInstance method를 호출할 때 동시에 호출할 수 없도록 synchronized를 추가한다.

한 thread가 해당 method를 모두 완료하고 나가고 나서야 호출할 수 있다. 

 

하지만 thread가 많다고하면

과도한 locking overhead가 존재한다.

 

 

해결 방안 2

uniqueInstance를 처음부터 생성해준다.

아래와 같이 하면 multi-thread여도 문제가 없고, lock overhead도 존재하지 않는다.

하지만 이 경우 누가 요청하지 않아도 미리 생성하는 것인데. (global variable과 동일)

메모리 효율성에서는 좋지 않다.

 

 

해결 방안 3

lock을 함수 진입에 하면 과도한 overhead가 존재하니 write할 때만 lock을 설정한다. (read 할 때는 lock 필요 없음)

lock 후, uniqueInstance 존재를 double-check한다.

(두 thread가 getInstance()함수에서 if문에 위치하고 A thread가 생성하고 나가고 B thread가 if문에서 들어온 뒤에 null확인이 없으면 새로 인스턴스를 생성하게 된다)

논리적으로는 문제가 없지만

실제로 돌려보면 가아끔 특수한 문제가 생긴다.

 

A thread가 instance를 생성하는 도중에

B thread가 생성 중인 instance를 read하고 이것저것 부르고 접근하려고 할텐데 

완전하게 생성되지 않았기 때문에 런타임에러가 날 수 있다. 

 

 

해결 방안 4

위 모든 문제를 해결하는 최종 코드이다. (java 1.5이후부터 가능)

 

 

반응형