📖 singleton[ˈsɪŋɡltən]
1.(단독) 개체
2.독신자(결혼을 안 했거나 애인이 없는 사람)
3.(쌍둥이가 아닌) 외둥이[단일아]
출처 - 옥스퍼드 영한사전
싱글톤 패턴은 객체의 인스턴스가 오직 1개만 생성되는 패턴을 의미한다. 최초 호출시 인스턴스를 메모리에 고정적으로 할당하고, 그 이후에 인스턴스를 호출할때는 최초에 생성된 인스턴스를 리턴한다.
싱글톤 패턴은 다음과 같은 상황에서 사용한다.
그러면 싱글톤 패턴을 쓰는 이유는 무엇일까?
고정된 메모리 영역에 최초 한번만 인스턴스를 생성하기 때문에 때문에 메모리 낭비를 방지할 수 있음
싱글톤으로 만들어진 클래스의 인스턴스는 전역 인스턴스이기 때문에 다른 클래스의 인스턴스들이 데이터를 공유하기 쉽다.
디자인 패턴은 특정한 코드나 규약을 의미하는것이 아닌 템플릿 형태로 일반화된 솔루션을 말하기 때문에 분명한 코드가 있는게 아니라 정의와 개념에만 맞게 구현하면 된다.
싱글턴 패턴이 필요한 상황(설정 객체)를 가정하여 구현해보자.
싱글턴 패턴은 외부에서 new 생성자를 이용해 구현하면 안되고, 메모리에 고정적으로 할당해야한다.
이를 고려하면 다음 키워드를 사용하여 구현할 수 있다.
요구조건 | 방법 |
---|---|
외부 new 생성자를 이용해 구현하면 안됨 | getInstance 메소드를 통해 내부에서 인스턴스 생성 |
메모리에 고정적으로 할당 | static 사용 |
public class Settings {
private static Settings instance;
private Settings() {}
public static Settings getInstance() {
if (instance == null) {
instance = new Settings();
}
return instance;
}
}
코드 1 - 싱글톤 패턴 적용
public static void main(String args[]) {
Settings instance1 = Settings.getInstance();
Settings instance2 = Settings.getInstance();
System.out.println(instance1 == instance2);
//True
Settings2 instance3 = Settings2.getInstance();
Settings2 instance4 = Settings2.getInstance();
System.out.println(instance3 == instance4);
//True
}
코드 2 - 메인함수
하지만 위 코드는 문제점을 가지고 있다.
코드 1의 싱글톤 패턴은 멀티스레드시 문제점이 발생한다. if문 도중에 컨택스트 스위칭이 발생하면 인스턴스가 중복생성이 될 수 있다. 순서없이 컨택스트 스위칭이 일어나는 영역(Critical Section, 임계구역)을 lock하여 동기화 할 필요가 있다.
그러면 멀티스레드를 해결 할 수 있는 코드를 만들어 보자.
1. Eager initialization
public class Setting2 {
private static Setting2 instance = new Setting2();
private Setting2() {};
public static Setting2 getInstance() {
return instance;
}
}
코드 3 - Eager initialization 방식의 싱글턴
멀티스레드 문제는 해결할 수 있지만 인스턴스를 요청하지 않아도 생성되기 때문에 효율적이지 않다.
2. synchronized
public class Settings3 {
private static Settings3 instance;
private Settings3() {}
public static synchronized Settings3 getInstance() {
if (instance == null) {
instance = new Settings3();
}
return instance;
}
}
코드 4 - synchronized 방식의 싱글턴
synchronized 방식을 쓰는 것 자체가 성능상 비효율을 초래한다.
3. static inner class
package singleton;
public class Settings4 {
private Settings4() {}
private static class SettingHolder {
private static final Settings4 INSTANCE = new Settings4();
}
public static Settings4 getInstance() {
return SettingHolder.INSTANCE;
}
}
코드 5 - static inner class 방식의 싱글턴
싱글톤 인스턴스가 많은 데이터를 공유할 경우 다른 클래스의 인스턴스들 간에 결합도가 높아져 "개방-폐쇄 원칙" 을 위배하게 된다.
멀티쓰레드환경에서 위와 같은 동기화처리를 하지 않으면 인스턴스가 두 개나 생성될 수 있다.
lifecycle을 제어하기 힘들다. 싱글톤이 제대로 garbage collecting이 되지 않으면 지속적으로 메모리를 점유하고 있을 가능성이 크다.
- 인프런 디자인패턴 - 백기선
- https://jeong-pro.tistory.com/86#recentComments