시스템 런타임, 환경 세팅에 대한 정보 등, 인스턴스가 여러개일 때 문제가 생길 수 있는 경우가 있음
인스턴스를 오직 한개만 만들어 제공하는 클래스가 필요
싱글톤 패턴이란?
- 인스턴스를 오직 한개만 제공하는 클래스
목적
1. 인스턴스를 오직 한개만 생성
2. 하나의 인스턴스에 글로벌하게 접근할 수 있는 방법을 제공
사용 예시
- java.lang.runtime
- 스프링에서 빈의 스코프 중에 하나로 싱글톤 스코프
- 다른 디자인 패턴(빌더, 퍼사드, 추상 팩토리 등) 구현체의 일부로 쓰이기도 함
구현 방법1. private 생성자에 static 메소드
public class Settings {
private static Settings instance;
private Settings() {};
public static Settings getInstance() {
if (instance == null) {
instance = new Settings();
}
return instance;
}
}
- 위 방법은 멀티쓰레드 환경에서 getInstance 호출하는 시점에 따라 인스턴스가 여러개 생성 될 수 있어서 안전하지 않음
L 두개의 쓰레드가 동시에 if 문 안으로 들어오면 인스턴스가 두개 생김
Tip1. 자바의 경우 private 생성자를 만들면 클래스 밖에서는 생성자를 사용할 수 없음
Tip2. 자바의 경우 static 함수를 제공하면 객체를 생성하지 않고 메소드를 사용할 수 있음
구현 방법2. 동기화를 사용해 멀티쓰레드 환경에 안전하게 만드는 방법
public class Settings {
private static Settings instance;
private Settings() {};
public static synchronized Settings getInstance() {
if (instance == null) {
instance = new Settings();
}
return instance;
}
}
- sychronized 키워드 사용해서 getInstance에 한번에 하나의 쓰레드만 블록 안으로 접근 하도록 설정
L 단점: getInstance를 사용할때마다 동기화처리하는 작업 때문에 성능에 불이익이 생길 수 있음
Tip3. 자바의 경우 sychronized 키워드 사용하면 한번의 하나의 쓰레드만 처리하게 할 수 있음
구현 방법3. 이른 초기화 (eager initialization)을 사용하는 방법
public class Settings {
private static final Settings INSTANCE = new Settings();
private Settings() {};
public static Settings getInstance() {
return INSTANCE;
}
}
- 단점: 인스턴스를 만드는 과정의 비용이 크다면 굳이 사용할 필요가 없는 경우에도 애플리케이션 로딩시 많은 리소스를 많이 사용할 수 있음
구현 방법4. double checked locking으로 효율적인 동기화 블럭 만들기
public class Settings {
private static volatile Settings instance;
private Settings() {};
public static Settings getInstance() {
if (instance == null) {
synchronized (Settings.class) {
if (instance == null) {
instance = new Settings();
}
}
}
return instance;
}
}
- 1번보다 효율적인 이유: 멀티쓰레드 환경에서 안전함
- 2번보다 효율적인 이유: getInstance를 사용할때마다 동기화가 걸리지 않음
- 3번보다 효율적인 이유: 실제 instance를 사용할때 생성함
- volatile을 써야해서 자바 1.5이상에서 동작
구현 방법5. static inner 클래스 사용하기
public class Settings {
private Settings() {};
private static class SettingsHolder {
private static final Settings INSTANCE = new Settings();
}
public static Settings getInstance() {
return SettingsHolder.INSTANCE;
}
}
특징
- 지연 로딩, 쓰레드 세이프티