헤드 퍼스트 디자인 패턴을 읽고 정리한 글입니다.
싱글턴 패턴 (Singleton Pattern)은 해당 클래스의 인스턴스가 하나만 만들어지고, 어디서든지 그 인스턴스에 접근 할 수 있도록 하기 위한 패턴입니다.
public class Singleton {
private static Singleton uniqueInstance;
private Singleton() {}
public static Singleton getInstance() {
if(uniqueInstance == null) {
// 인스턴스가 필요할 때 만들어 집니다. (Lazy Instantiation)
uniqueInstance = new Singleton();
}
return uniqueInstance;
}
}
위 방법은 멀티스레딩 환경에서 문제가 있습니다.
만약 getInstance 메소드에 동시에 두 개의 스레드가 접근했다고 가정해봅시다.
1번 스레드가 인스턴스를 생성하기 직전에 2번 스레드가 if 문에 접근한다면 두 스레드 모두 새로운 인스턴스를 만들게 됩니다. 즉, 두 개의 인스턴스가 만들어지게 되어 문제가 생깁니다.
public static Singleton getInstance() {
if(uniqueInstance == null) { // 2번 스레드 접근
// 1번 스레드 위치
uniqueInstance = new Singleton();
}
return uniqueInstance;
}
public class Singleton {
private static Singleton uniqueInstance;
private Singleton() {}
public static synchronized Singleton getInstance() {
if(uniqueInstance == null) {
uniqueInstance = new Singleton();
}
return uniqueInstance;
}
}
public class Singleton {
private static Singleton uniqueInstance = new Singleton();
private Singleton() {}
public static synchronized Singleton getInstance() {
return uniqueInstance;
}
}
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;
}
}
volatile 키워드가 필요한 이유는?
volatile은 Java 변수를 Main Memory에 저장하겠다는 것을 명시하는 것입니다.
만약 1번 스레드가 인스턴스를 생성하고 그 값이 Main Memory에 반영 되지 않고 CPU Cache에만 반영되었다면 2번 스레드가 인스턴스를 읽어올 때 동기화 문제가 생깁니다.
https://nesoy.github.io/articles/2018-06/Java-volatile