이전코드는 매번 인스턴스를 가져올 때마다 동기화를 획득했지만 개선된 코드에서는 객체를 생성해야 되는지 여부를 먼저 확인한 후 없을 경우에만 잠금을 걸어 속도향상을 기대할 수 있다.
public static SampleSingleton getInstance() {
if (instance == null) {
synchronized (SampleSingleton.class) {
if (instance == null) {
instance = new SampleSingleton();
}
}
}
return instance;
}
5. 전체코드
public class SampleSingleton {
private static volatile SampleSingleton instance;
private SampleSingleton() {
// private 생성자로 외부에서의 인스턴스 생성을 막음
}
public static SampleSingleton getInstance() {
if (instance == null) {
synchronized (SampleSingleton.class) {
if (instance == null) {
instance = new SampleSingleton();
}
}
}
return instance;
}
}
6. 추가적인 문제점
하지만 위의 코드들도 추가적인 문제점이 존재한다.
volatile 키워드가 필요하여 자바 1.4 이하 버전에서는 사용할 수 없다.
쓸데없이 코드가 길어 읽기 힘들어진다.
7. 다른 방법
Early Initialization
스레드 안전성을 달성하는 가장 쉬운 방법은 객체 생성을 인라인으로 설정하거나 동등한 static 메서드를 사용하는 것이다. 이는 static 필드와 메서드가 차례로 초기화된다는 사실을 활용한다.
public class SampleSingleton {
private static final SampleSingleton INSTANCE = new SampleSingleton();
public static SampleSingleton getInstance() {
return INSTANCE;
}
// private constructor and other methods...
}
Initialization on Demand
Java는 메서드나 필드 중 하나를 처음 사용할 때 클래스 초기화가 발생하기 때문에 아래와 같이 중첩된 static 클래스를 사용하여 지연 초기화를 구현할 수 도 있다.
public class InitOnDemandSingleton {
private static class InstanceHolder {
private static final InitOnDemandSingleton INSTANCE = new InitOnDemandSingleton();
}
public static InitOnDemandSingleton getInstance() {
return InstanceHolder.INSTANCE;
}
// private constructor and other methods...
}