싱글톤(Singleton) 패턴이란?
싱글톤 패턴이란 어떤 클래스의 인스턴스는 오직 1개만 생성할 수 있는 패턴이다. 즉 어느 시점에서 호출을 해도 같은 객체임을 보장한다.
장점
- 메모리 관리에 효율적이다.
- 프로그램이 실행되고 있는 동안 단 1개의 인스턴스만 생성해서 사용하기 때문에 메모리 관리에 효율적이다.
- 데이터 공유가 쉽다.
- 다른 클래스에서 호출해도 같은 객체를 사용하기 때문에 클래스들 간의 데이터 공유가 쉽다.
단점
- 동시성 문제
- 1개의 인스턴스를 공유하기 때문에 동시성 문제가 발생할 수 있다.
- 테스트하기 어렵다.
- 싱글톤 패턴을 사용하면 객체가 전역 상태를 가지고 있기 때문에 격리된 환경에서 수행해야 하는 테스트의 경우 매번 상태를 초기화해야 한다.
- 상속 불가능
- 기본 생성자를 private으로 선언하기 때문에 자식 클래스를 만들 수 없어 객체지향 언어의 핵심인 다형성을 적용하지 못한다.
싱글톤을 구현하는 구현하는 방법
1. Eager Initialization
가장 간단한 형태의 싱글톤 구현 방법이다. 클래스 로딩 단계에서 객체가 생성되기 때문에 인스턴스를 사용하지 않는다면 메모리 낭비가 될 수 있다.
class A {
private final static A INSTANCE = new A();
private A() {
}
public static A getInstance() {
return INSTANCE;
}
}
2. Lazy Initialization
Lazy Initialization은 객체를 얻으려고 getInstance를 호출하는 시점에 객체가 생성되지 않았다면 생성을 하고 객체를 반환하기 때문에 1번의 메모리 문제를 해결할 수 있다
class A {
private static A INSTANCE;
private A() {
}
public static A getInstance() {
if (INSTANCE != null) {
INSTANCE = new A();
}
return INSTANCE;
}
}
3. Thread Safe Singleton
싱글톤의 동시성 문제를 해결하기 위한 패턴이다. 하지만 synchronized 키워드에 대한 비용이 크기 때문에 가장 많이 호출되는 getInstance에 synchronized를 거는 방식은 성능 저하가 발생한다.
class A {
private static A INSTANCE;
private A() {
}
public static synchronized A getInstance() {
if (INSTANCE != null) {
INSTANCE = new A();
}
return INSTANCE;
}
}
4. Double Checked Locking
3번의 문제를 어느 정도 해결할 수 있는 개선된 구현 방법이다. synchronized를 인스턴스를 생성할 때만 synchronized가 동작하도록 한다.
class A {
private static A INSTANCE;
private A() {
}
public static A getInstance() {
if (INSTANCE != null) {
synchronized (A.class) {
INSTANCE = new A();
}
}
return INSTANCE;
}
}
5. Bill Pugh Singleton Implementaion
Bill Pugh가 고안한 방식으로 이전에 소개한 방식들의 문제점을 대부분 해결한 방식이다.
class A {
private A() {
}
private static class SingletonHelper {
private static final A INSTANCE = new A();
}
public static A getInstance() {
return SingletonHelper.INSTANCE;
}
}
SingletonHelper라는 내부 클래스를 하나 선언하고 내부 클래스의 필드로 A를 갖는다. 내부 클래스의 경우 getInstance가 호출되는 시점에 메모리에 로드되기 때문에 1번의 문제점과 synchronized를 사용했을 때 발생하는 성능저하 문제 또한 해결된다.
하지만 앞서 소개한 모든 방식은 직렬화 문제와 Java의 Refection으로 인해 파괴될 수 있는 문제가 있어서 다양한 대응방식이 있지만 가장 간단하게 공격을 방지하고 싱글톤을 보장하는 방법은 enum을 사용하는 것이다.
6. Enum
enum을 사용한다는 것이 코드상으로 어색함은 있지만 동시성 문제, 직렬화, Reflection 공격과 같은 문제를 가장 간단하게 해결할 수 있는 방법이다.
enum A {
INSTANCE;
public void hello() {
System.out.println("hello");
}
}
'자바' 카테고리의 다른 글
[디자인 패턴] 템플릿 메서드(Template Method) 패턴 (0) | 2024.03.18 |
---|---|
[디자인 패턴] 팩토리 메서드(Factory Method) 패턴 (0) | 2024.03.17 |
컬렉션 프레임워크(Collection Framework) (0) | 2022.12.09 |
Auto Boxing/UnBoxing (0) | 2022.12.09 |
Wrapper Class (0) | 2022.12.09 |