여러 스레드가 동시에 공유 자원에 접근하여 예상치 못한 결과가 발생하는 상황
메서드 전체에 synchronized 키워드를 사용하여, 한 번에 하나의 스레드만 해당 메서드에 접근할 수 있도록 보장
public class Singleton {
private static Singleton instance;
private Singleton() {
// 생성자는 private으로 외부에서 호출 불가
}
public synchronized static Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
설명
1. synchronized 키워드를 메서드에 사용하면 함수 전체가 하나의 락을 공유
2. 여러 스레드가 동시에 getInstance()를 호출하더라도, 락을 획득한 하나의 스레드만 객체를 생성하거나 반환
volatile, synchronized 키워드를 함께 사용하여, 객체 생성 시 더블-체크 잠금(Double-Checked Locking)을 구현
public class Singleton {
private volatile static Singleton instance;
private Singleton() {
// 생성자는 private으로 외부에서 호출 불가
}
public static Singleton getInstance() {
if (instance == null) {
synchronized (Singleton.class) { // 블록 단위 동기화
if (instance == null) { // 두 번째 확인
instance = new Singleton();
}
}
}
return instance;
}
}
설명
1. volatile 키워드는 가시성(Visibility)을 보장하여, 여러 스레드가 instance 변수의 최신 상태를 제공
2. 첫 번째 if (instance == null)에서 객체 생성 여부 확인
3. (Singleton.class) 블록 안에서 두 번째 확인을 통해 객체를 생성
래스 로더의 초기화 단계에서 JVM이 보장하는 스레드 안전성을 이용
static 내부 클래스에 싱글턴 객체를 생성
public class Singleton {
private Singleton() {
// 생성자는 private으로 외부에서 호출 불가
}
private static class LazyHolder {
private static final Singleton INSTANCE = new Singleton();
}
public static Singleton getInstance() {
return LazyHolder.INSTANCE;
}
}
설명
1. 내부 정적 클래스 LazyHolder는 Singleton 객체를 생성하고, 클래스가 로드될 때 초기화
2. getInstance()를 호출할 때 LazyHolder가 처음으로 로드되며, 이 시점에 Singleton 객체 생성
3. JVM의 클래스 초기화 규칙에 따라, 클래스 초기화는 스레드 안전하게 수행