싱글톤 패턴 구현 방법 4가지
싱글톤 패턴 구현 방법 4가지
1. static 을 활용한 방법
class BasicSingleton implements Serializable {
private BasicSingleton() {}
private static final BasicSingleton INSTANCE = new BasicSingleton();
public static BasicSingleton getInstance() {
return INSTANCE;
}
/**
* readResolve method 는 readObject 메소드에서 생성한 인스턴스를 다른 인스턴스로 바꿔준다. 만일 역직렬화 되는 객체의
* 클래스에서 readResolve 메소드를 다시 정의하면 그 객체가 역직렬화 된 후 그 결과로 새롭게 생성된 객체에 대해 이 메소드가
* 자동으로 호출되며, 이 메소드에서 반환하는 객체 참조가 역직렬화로 새롭게 생성된 객체 대신 반환된다.
**/
protected Object readResolve() {
return INSTANCE;
}
}
- 가장 기본적인 싱글톤 구현 방법이다.
- 클래스가 로드 될 때 jvm 에 의해 INSTANCE 가 생성되어 원하는 순간에 싱글톤 인스턴스를 생성하는 lazy loading 은 지원하지 못한다.
- 싱글톤 객체를 직렬화, 역직렬화를 하면 인스턴스가 두 개 생길 수 있다.
- 리플렉션을 사용해 BasicSingleton 을 생성하면 인스턴스가 두 개 생길 수 있다.
BasicSingleton instance = BasicSingleton.getInstance();
BasicSingleton newInstance;
Constructor[] constructors = BasicSingleton.class.getDeclaredConstructors();
for (Constructor constructor : constructors) {
constructor.setAccessible(true);
newInstance = (BasicSingleton) constructor.newInstance();
break;
}
System.out.println(instance == newInstance); // false
2. enum 을 활용한 방법
enum EnumBasedSingleton {
INSTANCE;
EnumBasedSingleton() {
value = 42;
}
private int value;
public int getValue() {
return value;
}
public void setValue(int value) {
this.value = value;
}
}
- java enum 의 내부에 선언된 모든 field 들은 한 번만 생성되고 직렬화,역직렬화 그리고 상속할 수 없는 특징을 이용해 싱글톤 구현
- 리플렉션, 직렬화 역직렬화를 해결할 수 있지만 lazy loading 은 해결할 수 없다.
3. lazy initialize, double check locking 싱글톤
public static LazySingleton getInstance() {
if (instance == null) {
synchronized (LazySingleton.class) {
if (instance == null) {
instance = new LazySingleton();
}
}
}
return instance;
}
- 클래스 로드 시 인스턴스가 생성되지 않고 필요할 때 생성된다.
- double check lock 으로 thread-safe 하기 위해 사용한 synchronized 키워드로 생기는 성능 저하를 해결한다.
- 여러 스레드가 메모리를 공유하는 경우 instance 생성이 완료되기 전에 다른 스레드가 instance 가 저장될 메모리 공간에 접근하는 문제가 드물게 발생할 수 있다.
4. InnerStatic 싱글톤
public class InnerStaticSingleton {
public class InnerStaticSingleton() {}
private static class Impl {
private static final InnerStaticSingleton INSTANCE = new InnerStaticSingleton();
}
public InnerStaticSingleton getInstance() {
return Impl.INSTANCE;
}
}
- 클래스 초기화 시 JVM 이 원자적으로 수행하는 특성을 활용해 synchronized 키워드 없이 thread-safe 하게 싱글톤 객체를 만들 수 있다.
- InnerStaticSingleton 클래스에서 Impl 클래스 변수를 가지고 있지 않아 클래스 로드 시에 초기화 되지 않는다.
- getInstance() 메소드 호출 시 Impl 의 초기화를 진행하기 때문에 lazy loading 을 할 수 있다.