티스토리 뷰
싱글톤 패턴은 스프링에서 빈의 스코프 중 하나이며 인스턴스를 오직 한 개만 제공하는 클래스를 말한다.
시스템 런타임, 환경 세팅에 대한 정보 등 인스턴스가 여러 개일 때 문제가 생길 수 있는 경우가 존재한다. 그럴 경우에 인스턴스를 오직 한 개만 만들어서 제공하는 클래스가 필요하다.
싱글톤을 실무에서 사용할 때는 다음과 같이 사용한다.
1. 자바의 java.lang.Runtime
2. 다른 디자인 패턴 (빌더, 퍼사드, 추상 팩토리 등) 구현체의 일부로 사용
* 싱글톤
- instance: Singleton
+ getInstance(): Singleton
싱글톤을 작성하는 경우는 다음과 같다.
1. 기본적인 뼈대 (Settings.class)
public class Settings {
... 기본적인 코드
}
이를 가져올 때는 다음처럼 가져온다.
Settings settings = new Settings();
잠깐! 여기서 알아야 할 것은
Settings settings = new Settings();
Settings settings1 = new Settings();
두 개를 선언했다고 했을 때, 과연 이 두개는 같은 인스턴스일까?
결과적으로 보면 아니다. 만약 System.out.println(settings == settings1)를 하게 된다면 False가 출력될 것이다.
그 이유는 각각 새로운 인스턴스이기 때문이다.
그러나 우리는 사용할 때, 위 처럼 직접 가져올 수 없도록 private로 선언하여 사용하여야 한다.
public class Settings {
private static Settings instance;
private Settings() {
}
public static Settings getInstance() {
if (instance == null) {
instance = new Settings();
}
return instance;
}
}
위 코드를 살펴보자.
우선 Settings에 인스턴스를 private로 선언한다. 그리고 인스턴스를 사용할 클래스에서 가져올 수 있도록 getInstance를 선언한다. 그리고 선언할 때마다 새로운 인스턴스가 생성되는 것이 아니라 기존에 인스턴스가 있다면 같은 인스턴스를 사용할 수 있도록 조건문을 사용하였다.
new를 사용하여 생성한 모든 인스턴스는 각각 다르다. 그러나 인스턴스 변수를 사용하고 조건문을 사용하여 해당 조건문을 지나면 이미 생성된 객체가 있을 경우에는 기존 객체를 가져오도록 한다.
그리고 이를 사용할 클래스에서 Settings settings = Settings.getInstance()로 가져와서 사용할 수 있다.
그러나 여기서 문제가 있다. 인스턴스를 생성할 때, 매번 다른 인스턴스가 아닌 같은 인스턴스로 생성하고 싶어서 조건문을 사용했지만 확인해보면 결국 다르다고 출력될 것이다.
그 이유는 첫 번째로 선언된 것이 조건문을 통과하자마자 두 번째로 선언한 것이 조건문으로 들어간다. 쉽게 말해서 Settings1을 선언하였고 Settings2를 선언하였다. Settings1이 조건문을 통과하자마자 Settings2도 조건문에 들어가게 된다. 그러면 Settings1은 new Settings()로서 생성이 되고 Settings2도 마찬가지로 new Settings()로 생성이 되어 서로 다른 인스턴스가 된다.
위의 문제를 해결하는 방법은 여러 가지가 있다.
synchronized
멀티 스레드 환경에서 동기화를 사용한다. 즉, synchronized를 사용하면 하나의 인스턴스가 조건문을 모두 통과할 때까지 다음 인스턴스는 멈춤 상태가 되어 있다.
public static synchronized Settings getInstance() {
if (instance == null) {
instance = new Settings();
}
return instance;
}
즉, synchronized를 사용하면 한 번에 하나의 스레드만 들어오도록 허락한다.
그러나 이 방법도 단점이 있다. 바로 동기화 처리 작업으로 인해 성능에 문제가 발생할 수 있기 때문이다.
이른 초기화 (eager initialization)
synchronized를 사용하고 싶지 않을 때는 이른 초기화를 사용하면 된다. 즉, 처음부터 생성하여 사용하는 것이다.
이른 초기화를 사용할 때는 다음과 같이 작성하면 된다.
private static final Settings INSTANCE = new Settings();
public static Settings getInstance() {
return INSTANCE;
}
그러나 이 또한 단점이 있다. 미리 만들어 사용하기 때문이다. 나중에 사용하지 않는 경우가 발생했을 시 문제가 된다.
Double Checked Locking
이 방법은 두 번 체크한다는 것을 의미한다. synchronized를 조건문 내부에서 사용한다.
조건문 내부에서 사용하는 것이 이전 방법보다 효율적인 이유는 매번 synchronized이 실행되는 것이 아니기 때문이다. 즉, 해당 메서드에 들어오는 모든 스레드에 동기화하는 것이 아니다. 그리고 필요한 시점에 만들 수 있는 것 또한 장점이다.
private static volatile Settings instanceDCL;
public static Settings getInstance() {
if (instanceDCL == null) {
synchronized (Settings.class) {
if (instanceDCL == null) {
instanceDCL = new Settings();
}
}
return instanceDCL;
}
double checked locking을 사용할 때 처음으로 선언하기 위해서는 꼭 volatile로 선언해야 한다.
Static Inner Class
내부 클래스로 먼저 선언하는 것을 말한다. 이 방법은 권장하는 방법 중 하나이다.
위의 방법들이 변수 선언한 것과 달리 이 방법은 변수는 필요없으며 생성자만 필요하다.이 방법의 장점은 멀티 스레드 환경에서 효율적이고 안전하다. 그리고 호출이 될 때, 로딩이 되기 때문에 Lazy Loading이 가능하다.
private static class SettingsHolder {
private static final Settings INSTANCE = new Settings();
}
private Settings() {
}
public static Settings getInstance() {
return SettingsHolder.INSTANCE;
}
잠깐! 다른 방법에서 생성자가 없는 것은 아니다.
다음은 실무에서 싱글톤을 사용할 때 아주 간단한 예시로 학습한다.
출처 - 백기선 유튜브 채널의 싱글톤 강의
'백엔드 > Spring' 카테고리의 다른 글
504 (Gateway Timeout) 에러 (0) | 2023.01.13 |
---|---|
싱글톤 (Singleton) 실무 (0) | 2021.10.24 |
session에 저장된 데이터를 JSP 파일에서 사용하기 (0) | 2021.03.26 |
- Total
- Today
- Yesterday
- 최종추가합격
- Default Branch
- 원티드 프리온보딩 챌린지
- 코딩테스트 대비
- 프론트엔드 챌린지
- 스프링
- 그룹인터뷰후기
- Frontend
- 깃허브 Merge
- 설명회느낌점
- 자바스크립트
- DB Error MongooseServerSelectionError
- 개발 이력서 지원 팁
- javascript
- 싱글톤
- 신입개발자가 준비해야 할 것들
- LottieFiles
- PostechAppleDeveloperAcademy
- node
- 원티드 프리온보딩
- 고민한 부분
- 포스텍애플디벨로퍼아카데미
- Express
- #포스텍애플디벨로퍼아카데미
- 포스텍애플아카데미
- React
- Singleton
- if(kakao)dev2022
- 개발자이력서꿀팁
- 조코딩과함께
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | ||||
4 | 5 | 6 | 7 | 8 | 9 | 10 |
11 | 12 | 13 | 14 | 15 | 16 | 17 |
18 | 19 | 20 | 21 | 22 | 23 | 24 |
25 | 26 | 27 | 28 | 29 | 30 | 31 |