싱글톤 패턴은 한정된 자원을 효율적으로 쓸 수 있도록 만들어준다.
Context
어떤 자원은 한정적인데 여러곳에서 또는 여러명이 사용해야하는 경우가 있다. 만약에 엘레베이터, 프린터, 정수기 등등이 될 수 있다. 이들은 필요할 때마다 생성하여 사용하기 어려운 사물들이다. 자 그럼 제한된 자원을 공유하여 사용해야하는데 이런경우 어떻게 해야할 수 있을까?
방향
- 생성자는 외부에 공개하지 않는다.
private static
의 자기 자신의 인스턴스를 가진다.public static getInstance():SelfClass
로 그 인스턴스가 null일 때는 생성해주고 아닌경우에는 그냥 해당 인스턴스를 반환한다.
위 방향을 모두 구현하면 아래 코드와 같다.
class LimitedResource {
private static LimitedResource instance = null;
private LimitedResource() { }
public static LimitedResource getInstance () {
if(instance == null) {
instance = new LimitedResource();
}
return instance;
}
}
Problem
사실 멀티쓰레드 환경이 아닌 경우에는 위 코드로 문제가 발생하지 않지만, 2개 이상의 스레드 환경에서는 문제가 발생할 수 있다.
이유로는 동시에 2개 이상의 스레드가 getInstance()
를 호출했을 경우 단 하나의 인스턴스만을 반환한다고 보장할 수 없기 때문이다.
- 동시의 2개 이상의 스레드가
getInstance()
를 호출한다. - 2개 이상의 스레드가 동시에
instance == null
문을 실행하여 모두true
를 반환한다. - 서로 다른 인스턴스 객체를 생성해 반환한다.
public class RegacyResource {
private static RegacyResource instance = null;
private RegacyResource() { }
public static RegacyResource getInstance () {
if(instance == null) {
try {
Thread.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
instance = new RegacyResource();
}
return instance;
}
}
try를 쓴 이유는 해당 경우를 효과적으로 재현하기 위해서다, 사실
Tread.sleep(1)
를 하지 않아도 필자의 컴퓨터에서는 2개 스레드의 경우 다른 인스턴스를 반환한다.
위 코드의 경우 아래 테스트를 돌리면 거의 대부분 테스트가 통과할 것이다.
public class RegacyResourceTest {
@Test
public void getInstanceInMultiThread() throws Exception {
RegacyResource[] resources = new RegacyResource[2];
new Thread(() -> {
resources[0] = RegacyResource.getInstance();
}).start();
new Thread(() -> {
resources[1] = RegacyResource.getInstance();
}).start();
Thread.sleep(10);
assertNotEquals(resources[0], resources[1]);
}
}
Solution
멀티스레드 환경에서의 해결 방법은 아래 2가지가 존재한다.
synchronized
키워드를 사용하여 메서드를 thread-safe하게 만든다.
public class SafetyResource {
private static SafetyResource instance = null;
private SafetyResource() { }
public synchronized static SafetyResource getInstance () {
if(instance == null) {
instance = new SafetyResource();
}
return instance;
}
}
static
변수를 바로 초기화하여 반환만 한다.
class SafetyResource2 {
private static SafetyResource2 instance = new SafetyResource2();
private SafetyResource2() { }
public static SafetyResource2 getInstance() {
return instance;
}
}
전자의 경우 많은 참조를 요구하면 한번에 한 스레드밖에 처리하지 못하므로 효율적이지 못하고, 아래의 경우 실제 사용하지 않는 경우가 많은 경우 효율적이지 못하다. 적절하게 사용하면 될 듯하다.
< 싱글턴 패턴의 모델이다>
Summary
싱글턴 패턴은 인스턴스가 오직 하나만 생성되는 것을 보장하고 어디에서든 이 인스턴스에 접근할 수 있도록 하는 디자인 패턴이다.
'소프트웨어 > 디자인패턴' 카테고리의 다른 글
[소프트웨어] 디자인 패턴에 대해서 (0) | 2017.01.23 |
---|---|
[소프트웨어/디자인패턴] 옵저버 패턴(Observer Pattern) (0) | 2017.01.23 |
[소프트웨어/디자인패턴] 커맨드 패턴(Command Pattern) (2) | 2017.01.21 |
[소프트웨어/디자인패턴] 스테이트 패턴(State Pattern) (0) | 2017.01.19 |
[소프트웨어/디자인패턴] 스트레티지 패턴(Strategy Pattern) (0) | 2017.01.19 |