생성 (1) - 싱글톤(Singleton) 패턴
- 클래스의 인스턴스를 하나만 생성하여 사용
- 셋팅 정보 같이 인스턴스가 여러 개 일경우 문제가 발생하는 경우를 막는다
- 1개 JVM 당 1개의 인스턴스만 갖음
구현
- 생성자를
private
으로 제한해 외부에서 인스턴스를 생성하지 못하게 한다 (new
금지) - 클래스의 인스턴스에 접근할 수 있는
public static
메서드를 만들어 제공한다
1. Eager Initialization (이른 초기화)
- 프로그램 시작시 정적 바인딩을 통해 메모리에 올리는 방식
- 사용하지 않을 수도 있는 자원을 생성하여 메모리낭비를 유발
- 멀티쓰레딩 문제가 발생하지 않는다
public class Settings {
private static Settings instance = new Settings();
private Settings() {}
public static Settings getInstance() {
return instance
}
}
public class Main {
public static void main(String[] args) {
Settings settings1 = Settings.getInstance();
Settings settings2 = Settings.getInstance();
System.out.println(settings1 == settings2) // true
}
}
2. Lazy Initialization (늦은 초기화)
- 인스턴스가 필요한 시점에 동적 바인딩을 통해 인스턴스를 생성하는 방식
- 멀티쓰레드 환경에서 싱글톤을 보장하기 위해
synchronized
사용 - 사용 전까지 메모리를 사용하지 않는 장점을 갖는다
- 단점 :
getInstance()
가 실행될 때 마다 동기화처리를 하기 때문에 성능저하 유발
public class Settings {
private static Settings instance;
private Settings() {}
public static synchronized Settings getInstance() {
if (instance == null) {
instance = new Settings();
}
return instance
}
}
- Double Checking Locking(DCL, Thread-safe)
- 성능저하를 유발하지 않기 위해 인스턴스가 생성되지 않은 경우만 동기화 블럭이 실행되도록 설정
public class Settings {
private volatile static Settings instance;
private Settings() {}
public static Settings getInstance() {
if (instance == null) {
synchronized (Settings.class) {
if (instance == null) {
instance = new Settings();
}
}
}
return instance
}
}
-
volatile
키워드는 멀티쓰레드 환경에서 인스턴스 초기화 하는 과정이 올바르게 진행될 수 있도록 해준다 - 첫번째 if문에서 인스턴스가 생성되지 않은 경우 동기화블럭에 접근해 한번더 존재 유무를 체크하고 인스턴스를 생성한다
- 이후 재호출시 인스턴스가 존재하기 때문에 동기화블럭을 접근하지 않는다
문제점
- 직렬화/역직렬화 : 클래스를 직렬화할 때 새로운 인스턴스가 생성된다
- 리플렉션 : 리플렉션을 이용하면 런타임에 private 생성자에 접근하여 새로운 인스턴스를 생성된다
3. Enum 사용
- Enum 클래스는 상수가
public static final
이며 생성자가private
이다 - Enum을 사용하면 위의 동기화, 직렬화, 리플렉션 문제를 모두 해결할 수 있다
public enum Settings {
INSTANCE;
}
장점
- 메모리를 효율적으로 사용할 수 있다
- 하나의 인스턴스만 사용하기 때문에 여러 인스턴스가 생성되는 것으로부터 메모리 낭비를 방지
- 데이터 공유가 쉽다
- 싱글톤 인스턴스는 전역으로 사용되기 때문에 다른 클래스에서 접근하기 쉬워진다
단점
- 역할이 커지면 결합도가 높아지며 OCP를 위배할 수 있다