5. Singleton - 인스턴스를 단 하나만 만든다
5. Singleton - 인스턴스를 단 하나만 만든다
- 지정한 클래스의 인스턴스가 반드시 1개만 존재한다는 것을 보증하고 싶을 때
- 인스턴스가 하나만 존재한다는 것을 프로그램 상에서 표현하고 싶을 때
인스턴스가 하나만 존재하는 것을 보증하는 패턴을 Singleton 패턴이라고 한다.
외부에서 생성자 호출을 금지하기 위해서 Singleton 클래스의 생성자는 private 이다.
예제
싱글톤(Singleton) 패턴은 소프트웨어 디자인 패턴 중 하나로, 클래스의 인스턴스가 오직 하나만 생성되도록 보장하는 패턴입니다. 이 패턴을 사용하면 어떤 클래스에서도 해당 클래스의 단일 인스턴스에 접근할 수
있으며, 이를 통해 전역적으로 데이터를 공유하거나 객체의 상태를 유지할 수 있습니다. 자바에서 싱글톤 패턴을 구현하는 일반적인 방법은 다음과 같습니다:
- 생성자를 private으로 선언: 클래스의 생성자를 private으로 선언하여 외부에서 인스턴스를 직접 생성할 수 없도록 합니다.
- 정적 변수(private): 클래스 내부에 해당 클래스의 유일한 인스턴스를 저장할 정적(private) 변수를 선언합니다.
- 정적 메서드: 클래스 내부에 유일한 인스턴스를 반환하는 정적(public) 메서드를 제공합니다. 이 메서드는 클래스의 유일한 인스턴스를 생성하거나 이미 생성된 인스턴스를 반환합니다.
- 지연 초기화(Lazy Initialization): 인스턴스가 필요한 시점에서 생성하도록 지연 초기화를 적용할 수 있습니다. 즉, 처음으로 인스턴스가 요청될 때 생성하고, 이후에는 항상 동일한 인스턴스를
반환합니다. - 스레드 안전성: 멀티스레드 환경에서 안전한 싱글톤을 보장하기 위해 스레드 동기화를 고려해야 합니다. 이를 위해 두 가지 주요 방법이 있습니다. 첫 번째로는 인스턴스를 미리 생성하는 Eager
Initialization 방식과, 두 번째로는 지연 초기화를 사용하되 스레드 동기화를 적용하는 방식입니다.
여기에 예시로 자바에서 싱글톤 패턴을 구현한 코드가 있습니다:
public class Singleton {
private static Singleton instance;
// private 생성자로 외부에서 인스턴스 생성 불가능
private Singleton() {
}
// 인스턴스 반환하는 정적 메서드
public static Singleton getInstance() {
if (instance == null) {
synchronized (Singleton.class) {
if (instance == null) {
instance = new Singleton();
}
}
}
return instance;
}
}
이 코드에서는 인스턴스를 처음 요청할 때 생성하고, 이후에는 항상 동일한 인스턴스를 반환하도록 구현되어 있습니다. 또한, 스레드 동기화를 사용하여 멀티스레드 환경에서도 안전하게 작동하도록 보장합니다.
지연 초기화 미적용
지연 초기화를 하지 않은 싱글톤 패턴의 코드는 다음과 같이 간단하게 구현할 수 있습니다:
public class EagerInitializedSingleton {
// 클래스 로딩 시점에서 인스턴스를 생성 (즉, 클래스가 로드될 때 인스턴스가 생성됨)
private static final EagerInitializedSingleton instance = new EagerInitializedSingleton();
// private 생성자로 외부에서 인스턴스 생성 불가능
private EagerInitializedSingleton() {
}
// 항상 동일한 인스턴스를 반환
public static EagerInitializedSingleton getInstance() {
return instance;
}
}
이 코드에서는 클래스가 로딩될 때 instance
변수가 즉시 생성되어 초기화됩니다. 이렇게 하면 지연 초기화가 없으며, 클래스가 로드될 때 이미 인스턴스가 생성되므로 스레드 안전성 문제는 없습니다. 그러나 이 방식은 애플리케이션 초기화 시간에 인스턴스를 생성하므로 애플리케이션이 실행될 때 무거운 작업을 수행하는 경우에는 부적합할 수 있습니다.
지연 초기화 적용
자바에서 지연 초기화와 스레드 안정성을 갖춘 싱글톤 패턴을 구현한 예제 코드를 제공합니다. 아래는 각각의 예제 코드입니다.
지연 초기화를 갖춘 싱글톤 패턴 예제 코드
public class LazyInitializedSingleton {
private static LazyInitializedSingleton instance;
// private 생성자로 외부에서 인스턴스 생성 불가능
private LazyInitializedSingleton() {
}
// 인스턴스를 처음 요청할 때 생성하고, 이후에는 항상 동일한 인스턴스 반환
public static LazyInitializedSingleton getInstance() {
if (instance == null) {
instance = new LazyInitializedSingleton();
}
return instance;
}
}
이 예제에서는 인스턴스를 처음 요청할 때 생성하므로 지연 초기화가 구현되어 있습니다. 그러나 이 코드는 멀티스레드 환경에서는 안전하지 않습니다.
스레드 안정성 확보
스레드 안정성을 갖춘 싱글톤 패턴 예제 코드
public class ThreadSafeSingleton {
private static ThreadSafeSingleton instance;
// private 생성자로 외부에서 인스턴스 생성 불가능
private ThreadSafeSingleton() {
}
// 스레드 동기화를 사용하여 인스턴스를 안전하게 생성하고 반환
public static synchronized ThreadSafeSingleton getInstance() {
if (instance == null) {
instance = new ThreadSafeSingleton();
}
return instance;
}
}
이 예제에서는 getInstance
메서드에 synchronized
키워드를 사용하여 스레드 동기화를 적용하고, 인스턴스를 생성하도록 하였으므로 멀티스레드 환경에서 안전합니다. 그러나 스레드 동기화로 인해 성능이 약간 저하될 수 있습니다.
두 예제 모두 싱글톤 패턴을 구현하고, 외부에서의 인스턴스 생성을 막기 위해 생성자를 private으로 선언하고, 처음 요청 시에만 인스턴스를 생성하며, 그 이후에는 항상 동일한 인스턴스를 반환합니다. 스레드 안정성을 갖춘 버전은 스레드 동기화를 통해 여러 스레드에서 안전하게 사용할 수 있도록 보장합니다.