싱글톤 패턴이란?
- 특정 클래스가 단 하나만의 인스턴스를 생성하여 사용하기 위한 패턴
- 생성자를 여러 번 호출하더라고 하나의 인스턴스를 보장해준다.
- Socket Connection, DB JDBC Connection, Spring Bean 등 사용
장단점
장점
유일한 인스턴스
: 인스턴스는 앱 전역에서 단 하나만을 보장해주기 때문에 일관된 상태 및, 접근이 용이하다.메모리 절약
: 동일한 객체를 중복생성 해주지 않아도 되기때문에 메모리를 절약할 수 있다.지연 초기화
: 인스턴스가 실제로 사용되는 시점에 생성하여 초기 비용을 줄일 수 있다.
단점
결합도 증가
: 싱글톤 패턴은 전역에서 접근을 허용하기 때문에 해당 인스턴스에 의존하는 경우 결합도가 증가할 수 있다.테스트 복잡성
: 싱글톤 클래스를 의존하는 클래스는 결합도 증가로 인해 테스트가 어려울 수 있다.상태 관리의 어려움
: 만약, 싱글톤 클래스가 상태를 가지고 있는 경우 전역에서 사용되어 변경될 수 있다. 이로 인해 예상치 못한 동작이 발생할 수 있다.
구현 예제
이른 초기화(Eager Initialization)
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;
}
}
- 클래스 로더가 초기화하는 시점에
정적 바인딩
을 통해 해당 인스턴스를 메모리에 등록하기 때문에Thread-safe
하다. - 객체를 미리 생성 하기 때문에 해당 인스턴스를 사용하지 않으면 메모리 측면에서 손해
지연 초기화(Lazy Initialization)
1
2
3
4
5
6
7
8
9
public class Singleton {
private Singleton(){}
private static final Singleton singleton = new Singleton();
public static Singleton getInstance() {
return singleton;
}
}
getInstance()
를 최초로 실행할 때에만 객체를 생성 하기 때문에 메모리 효율이 좋다.Trhead-safe
하지 않다.
지연 초기화, 동기화 처리(Lazy Initialization with synchronized)
1
2
3
4
5
6
7
8
9
10
11
public class Singleton {
private static Singleton instance;
private Singleton() { }
public static synchronized Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
- 메모리를 효율적으로 사용하며,
Tread-safe
하다 - 매번 호출시 동기화때문에 성능이 떨어진다.
LazyHolder - 지연 초기화, Static Inner Class 사용
1
2
3
4
5
6
7
8
9
10
11
public class Singleton {
private Singleton() { }
private static class SingletonHolder {
public static final Singleton INSTANCE = new Singleton();
}
public static Singlton getInstance() {
return SingletonHolder.INSTANCE;
}
}
getInstance()
가 호출될 때SingletonHolder
클래스가 호출이 되면서 실제 인스턴스가 만들어지기 때문에 성능 이슈가 없다.리플렉션
을 이용하여 생성자를 생성하면 싱글톤을 깨뜨릴 수 있다.
열거 타입(enum) 사용
1
2
3
4
5
6
7
8
9
enum Singleton {
INSTANCE;
private int value = 3;
public int getValue() {
return value;
}
}
- 절대적으로 싱글톤을 보장해준다.
- enum 기본 특성 때문에 다른 클래스 상속이 불가능하다
- 클래스 로드하는 순간 미리 생성한다.
마치며
열거타입
orLazyHolder
방법을 사용하자