[Java] 싱글턴 패턴(Singleton pattern)
싱글턴 패턴이란?
싱글턴(Single) 패턴은 프로그램 전체에서 오직 하나의 인스턴스만 존재하도록 보장하는 디자인 패턴이다. 주로 공통된 설정이나 자원, 전역적으로 접근해야 하는 객체에 사용된다.
- 설정 관리 객체
- 로그 기록 객체
- DB 연결 객체
Spring 프레임워크에서는 싱글턴 패턴을 기본적으로 적용한다.
빈(Bean) 하나를 만들어서 앱 전역에 공유하는 방식
주요 특징
- 인스턴스 하나만 생성됨
- 클래스가 최초 한 번만 객체를 생성함
- 전역 접근 가능
- 어디서든 동일한 인스턴스에 접근 가능
- 생성 제어
- 외부에서 직접
new하지 못하도록 생성자를 막음
예제1️⃣
1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class Singleton {
private static Singleton instance;
// ⭐ 생성자 private → 외부에서 new Singleton() 불가능
private Singleton() {}
public static Singleton getInstance() {
if (instance == null) {
instance = new Singleton(); // 처음 호출될 때 생성
}
// ⭐ 이미 생성된 인스턴스가 있다면 그것을 반환한다.
return instance;
}
}
- 생성자가
private인지 확인
멀티쓰레드 환경에서의 문제점
하지만 위 예제1️⃣ 방식은 멀티쓰레드 환경에서 동시에 여러 인스턴스가 생성될 때 문제가 생긴다. 이를 방지하기 위해 보통 동기화(Synchronized)를 사용하거나, 이른 초기화(Eager Initialization) 또는 Double-Checked Locking을 사용한다.
Double-Checked Locking
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public class Singleton {
private static volatile Singleton instance;
private Singleton() {}
public static Singleton getInstance() {
if (instance == null) { // 1차 체크
synchronized (Singleton.class) {
if (instance == null) { // 2차 체크
instance = new Singleton();
}
}
}
return instance;
}
}
volatile키워드
- Java 변수를 Main Memory에 저장하겠다라는 것을 명시하는 것
- 변수의 값을 Read할 때마다 CPU cache에 저장된 값이 아닌 Main Memory에서 읽는 것
- 또한, 변수의 값을 Write할 때마다 Main Memory에 까지 작성하는 것
synchronized키워드
- synchronized로 지정된 임계영역은 한 스레드가 이 영역에 접근하여 사용할때 lock이 걸림으로써 다른 스레드가 접근할 수 없게 된다.
- lock은 해당 객체당 하나씩 존재한다.
- synchronized로 설정된 임계영역은 lock 권한을 얻은 하나의 객체만이 독점적으로 사용한다.
이른 초기화 방식 (Thread-safe)
1
2
3
4
5
6
7
8
9
public class Singleton {
private static final Singleton instance = new Singleton(); // ✅
private Singleton() {}
public static Singleton getInstance() {
return instance;
}
}
장단점 요약
| 장점 | 단점 |
|---|---|
| 메모리 절약 | 테스트하기 어려움 (전역 상태) |
| 전역 인스턴스 공유 | 의존성 주입이 어려움 |
| 접근이 간편 | 멀티스레드 환경에서는 주의 필요 |