정의
- Singleton Pattern은 해당 Class의 instance가 하나만 만들어진다.
- 어디서든 그 instance에 접근할 수 있게 한다.
- class에서 하나뿐인 instance를 관리하게 한다.
- Instance가 사용될 때 똑 같은 instance를 만드는 것이 아닌, 동일 instance를 사용하게끔 하는 것이다.
고전적인 Singleton Pattern
public class Singleton {
private static Singleton uniqueInstance;
private Singleton(){}
public static Singleton getInstance() {
if(uniqueInstance == null){
uniqueInstance = new Singleton();
}
return uniqueInstance;
}
}
- 전역변수로 instance를 생성하는데 private static 키워드를 사용한다.
- Static이 붙은 class 변수는, 인스턴스화에 상관없이 사용할 수 있다.
- 하지만, private 접근 제어자로 인해
Singleton.uniqueInstance
- 와 같은 방법으로 접근할 수 없다.
- 이 상태에서 private 키워드를 붙이는데 그러면 new 키워드를 사용할 수 없게 된다.
- 그 결과 외부 class가 위 class의 instance를 가질 수 있는 방법은, getinstance() method를 사용하는 방법밖에 없다.
- 하지만 위의 방법은 Multi-threading과 관련해서 문제가 생긴다.
- 그 이유는 thread로 getinstance() method를 호출하면 instance가 두 번 생길 수 있기 때문이다.
- 이러한 문제를 방지하기 위해, getinstance() method를 동기화 시킨다.
public class Singleton {
private static Singleton uniqueInstance;
private Singleton() {}
public static synchronized Singleton getInstance() {
if (uniqueInstance == null) {
uniqueInstance = new Singleton();
}
return uniqueInstance;
}
}
- 위와 같이 할 수 있는데 이 방법도 문제가 있다. 수 많은 thread들이 getinstance() method를 호출하기 위해 동기화 하면 성능이 떨어진다.
- 이러한 문제를 방지하기 위해서 instance를 필요할 때 생성하는 것이 아니라, 처음부터 생성하는 방법이 있다.
public class Singleton {
private static Singleton uniqueInstance = new Singleton();
private Singleton() {}
public static Singleton getInstance() {
return uniqueInstance;
}
}
- 위와 같이 하는 방법 외에도 DCL(Double-Checking Locking)을 사용하여 getinstance()에서 동기화되는 부분을 줄이는 방법이 있다.
- DCL을 사용하면 instance가 생성되어 있는지 확인한 후, 생성이 되어있지 않을 때만 동기화를 할 수 있다.
- Volatile 키워드를 사용해서 multi-threading을 사용하더라도, 변수가 Singleton instance로 초기화 되는 과정이 올바르게 할 수 있다.
public class 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;
}