싱글턴과 동기화
2008/12/28 15:15싱글턴을 구현하다가, Head First Design Patterns에서 싱글턴에 관한 문제점을 읽었던 기억이 나서, 책을 뒤적여봤다. 일반적으로 Singleton은 다음과 같이 구현한다.
public class Singleton {
private static Singleton uniqueInstance;
// 기타 인스턴스 변수..
private Singleton() {}
public static Singleton getInstance() {
if (unuqueInstance == null) {
uniqueInstance = new Singleton();
}
return uniqueInstance;
}
// 기타 메소드..
}
하지만, 위 방법은 멀티쓰레딩에서 문제점이 있다. if문 안쪽 부분이 동기화가 되지 않으면, 인스턴스가 두개 이상 생성될 수 있다. 가장 간단한 해결책은 getInstance를 synchronized로 선언하는 것이지만, 속도가 수십배 느려질 수 있다. (책의 주장에는 메소드를 통째로 동기화하면, 100배까지 느려질 수도 있다고 한다.)
세가지 해결책이 있다.
- getInstance()의 속도가 그리 중요하지 않으면, 그냥 synchronized로 한다.
- 인스턴스를 lazy binding을 하지 말고, 처음부터 만든다.
- DCL(Double Checking Locking)을 써서 동기화 되는 부분을 줄인다.
2번은 그냥 위 코드에서, uniqueInstance를 선언할 때에 인스턴스를 생성하란 소리다.
public class Singleton {
private static Singleton uniqueInstance = new Singleton();
// 생략..
책임을 JVM에게 넘기게 되고, 코드는 가장 깔끔하긴 한데, 일단 사용되지 전에도 인스턴스를 차지하고 있고, 몇몇 문제들이 있다고 한다. 다음은 DCL을 쓰는 방법.
public class Singleton {
private volatile static Singleton uniqueInstance;
// 기타 인스턴스 변수..
private Singleton() {}
public static Singleton getInstance() {
if (unuqueInstance == null) {
synchronized (Singleton.class) {
if (unuqueInstance == null) {
uniqueInstance = new Singleton();
}
}
}
return uniqueInstance;
}
// 기타 메소드..
}
당연하지만, 안쪽의 if문을 없애면 안된다. 인스턴스가 두개 이상 생성될 수 있다. 그래서 Double Checking이다. 반면, 성능은 1번에 비해서 빠르고, 2번의 단점도 없다. 타이핑 하기 좀 귀찮다는 것 정도? =_=;
1~3번 중에 입맛대로 골라쓰면 되겠다. 코드의 출처는 Head First Design Patterns이다.

