Learn/Architecture
[Design Pattern] Singleton Pattern
push and sleep
2022. 8. 31. 00:38
# 개요
인스턴스가 단 하나만 만들어지게 하고싶을 때 사용하는 패턴
(예시) Thread Pool Manager은 여러개면 그들간의 조율이 필요하므로 하나만 있는게 좋다.
싱글톤은 new로 인스턴스를 생성하는게 아니라 getInstance 함수로 얻는다.
# 기본 구조
- 일반적인 생성자와는 달리 접근하지 못하도록 private로 생성자를 만든다.
- 생성자를 만들지 않으면 자바가 알아서 public으로 생성하므로 꼭 만들어줘야한다.
- 외부에서는 getInstance를 통해서만 인스턴스를 얻을 수 있다.
- 외부에서 이 함수에 바로 접근할 수 있게 static으로 선언해야 한다.
- 생성자를 대신하므로 public으로 열어줘야 한다.
- uniqueInstance는 클래스에 단 하나만 있어야 하므로 static으로 만든다.
- 외부에서 마음대로 조작하지 못하게 private로 만든다.
public class Singleton {
private static Singleton uniqueInstance;
// other useful instance variables
private Singleton() {}
public static Singleton getInstance() {
// 한번만 생성되도록 함
if (uniqueInstance == null) {
uniqueInstance = new Singleton();
}
return uniqueInstance;
}
// other useful methods
}
# Singleton on Multi-threads
싱글톤은 멀티 쓰레드에서 잘 작동하지 않는다.
- 아래와 같이 타이밍이 엇갈리면 제대로 작동하지 않는다.
해결책 1
getInstance 함수에 synchronized 키워드를 붙여준다.
- synchronized 함수는 하나의 쓰레드에서 사용되면 lock이 걸린다.
잘 동작하지만 문제는 이렇게 작성하면 성능에 영향을 준다.
- 두 번째 쓰레드부터는 딱히 필요가 없다.
해결책 2
아래와 같이 uniqueInstance를 선언해줄 때 인스턴스를 만들어준다.
성능 문제는 해결되지만 무조건 인스턴스를 만들기 때문에 메모리 사용 측면에서는 좋지 않다.
public class Singleton {
private static Singleton uniqueInstance = new Singleton();
// other useful instance variables
private Singleton() {}
public static Singleton getInstance() {
return uniqueInstance;
}
// other useful methods
}
해결책 3
자바 1.5부터 volatile이라는 키워드를 제공한다.
그리고 getInstance에서는 double-checked locking을 적용한다.
public class Singleton {
private volatile static Singleton uniqueInstance = null;
// other useful instance variables
private Singleton() {}
public static Singleton getInstance() {
if (uniqueInstance == null) {
synchronized(Singleton.class) {
if (uniqueInstance == null)
uniqueInstance = new Singleton();
}
}
return uniqueInstance;
}
// other useful methods
}
# QUIZ
SingletonA 클래스와 SingletonB 클래스가 각각 싱글톤 패턴으로 구현되었다고 가정할 때, 다음 코드의 수행결과를 쓰시오.
정답
각 클래스별로 같은게 나오므로 1, 2가 출력된다.