Ch5. 싱글턴 패턴 : 하나뿐인 특별한 객체 만들기

싱글턴패턴은 특정 클래스에 객체 인스턴스가 하나만 만들어지도록 하는 패턴이다.

고전적인 싱글턴 패턴 구현법

public class Singleton {
	private static Singleton uniqueInstance;

	//기타 인스턴스 변수

	private Singleton() {}

	public static Singleton getInstance() {
		if (uniqueInstance == null) {
			uniqueInstance = new Singleton();
		}
	}
	return uniqueInstance;
}

위와 같이 인스턴스가 필요한 상황이 닥치기 전까지 인스턴스를 생성하지 않는 방법을 ‘게으른 인스턴스 생성(lazyinstantiation)’ 이라고 한다.

  • 인스턴스가 2개 이상이 되지 않도록 함

  • 레지스트리 설정, 연결 풀, 스레드 풀과 같은 자원풀을 관리하는데 자주 쓰임

  • 생성자가 private

싱글턴 패턴

💡 싱글턴 패턴(Singleton Pattern)은 클래스 인스턴스를 하나만 만들고, 그 인스턴스로의 전역 접근을 제공한다.

  • 싱글턴 패턴을 실제로 적용할 때는 클래스에서 하나뿐인 인스턴스를 관리하도록 만든다. 그리고 다른 어떤 클래스에서도 자신의 인스턴스를 추가로 만들지 못하게 해야한다.

    • 인스턴스가 필요하다면 반드시 클래스 자신을 거치도록 해야함

  • 어디서든 그 인스턴스에 접근할 수 있도록 전역 접근 지점을 제공한다. 언제든 이 인스턴스가 필요하면 클래스에 요청할 수 있게 만들어놓고, 요청이 들어오면 그 하나뿐인 인스턴스를 건네주도록함.

멀티스레딩 문제 해결하기

2개의 스레드에서 위의 싱글톤 클래스 getInstance()를 실행한다고 가정하면 두개의 다른 인스턴스를 반환할 수 있음.

→ getInstance()를 동기화하면 멀티스레딩과 관련된 문제를 해결 가능.

public class Singleton {
	private static Singleton uniqueInstance;

	//기타 인스턴스 변수

	private Singleton() {}

	public static synchronized Singleton getInstance() {
		if (uniqueInstance == null) {
			uniqueInstance = new Singleton();
		}
	}
	return uniqueInstance;
}

그러나 속도 이슈가 있을 수 있다. 메소드를 동기화하면 성능이 100배정도 저하됨

→ 인스턴스가 필요할 때는 생성하지 말고 처음부터 만든다.

public class Singleton {
	private static Singleton uniqueInstance = new Singleton();

	private Singleton() {}

	public static synchronized Singleton getInstance() {
		return uniqueInstance;
}

이런 방법을 사용하면 클래스가 로딩될 때 JVM에서 Singleton의 하나뿐인 인스턴스를 생성해준다.

JVM에서 하나뿐인 인스턴스를 생성하기 전까지 그 어떤 스레드도 uniqueInstance 정적 변수에 접근할 수 없다.

→ DCL을 써서 동기화되는 부분을 줄인다.

DCL (Double-Checked Locking)을 사용하여 인스턴스가 생성되어 있는지 확인한 다음 생성되어 있지 않았을 때만 동기화 할 수 있다.

public class Singleton {
	private volatile static Singleton uniqueInstance;

	//기타 인스턴스 변수

	private Singleton() {}

	public static Singleton getInstance() {
		if (uniqueInstance == null) {
			synchornized (Singleton.class) {
				if (uniqueInstance == null) {
					uniqueInstance = new Singleton();
				}
		}
	}
	return uniqueInstance;
}

volatile 키워드를 사용하면 멀티스레딩을 쓰더라도 uniqueInstance 변수가 Singleton 인스턴스로 초기화되는 과정이 올바르게 진행된다.

문제점들

  • 모든 메소드와 변수가 static 으로 선언된 클래스도 유사하지만, 복잡한 초기화가 필요 없는 경우에만 사용 가능

  • 클래스로더마다 서로 다른 네임스페이스를 정의하기에 클래스로더가 2개 이상이면 같은 클래스를 여러번 로딩 가능하므로, 클래스 로더가 여러개라면 싱글턴을 조심해서 사용해야함

  • 리플렉션, 직렬화, 역직렬화도 싱글턴에서 문제가 될 수 있다.

enum 사용하기

위의 문제들을 enum으로 싱글턴을 생성해서 해결할 수 있다.

public enum Singleton {
	UNIQUE_INSTANCE;
	// 기타 필요한 필드
}

public class SingletonClient {
	public static void main (String[] args) {
		Singleton singleton = Singleton.UNIQUE_INSTANCE;
		// 여기서 싱글턴 사용
	}
}

Last updated