Java/Design Pattern

[Design Pattern] Singleton Pattern(싱글톤 패턴)이란

SeungbeomKim 2023. 11. 3. 18:01

 

오늘은 메모리 낭비를 방지할 수 있는 디자인 패턴인 싱글톤 패턴에 대해 알아보겠습니다.

singleton-design-pattern

 

Singleton Pattern

  • 애플리케이션이 시작될 때, 생성자가 여러 차례 호출되더라도 실제로 생성되는 객체는 하나이고 최초 생성 이후에 호출된 생성자는 최초의 생성자가 생성한 객체를 리턴하는 패턴
  • 즉, 처음에 생성한 인스턴스를 지속적으로 사용하는 패턴입니다
  • Java에서는 생성자를 Private으로 선언하고 다른 곳에서 생성하지 못하도록 만들고, getInstance() 메서드를 통해 받아서 사용하도록 구현

주로, 데이터베이스에서 Connection Pool, Thread Pool처럼 공통된 객체를 여러개 생성해서 사용하는 상황에서 사용합니다. 

 

이제 장단점에 대해 설명드리겠습니다. 

 

장점

  • 객체를 생성할 때 마다 메모리 영역을 할당받아야 하고, 한 번에 new 키워드를 통해 객체를 생성한다면 메모리 낭비를 방지할 수 있습니다.
  • 싱글톤으로 구현한 인스턴스는 "전역" 범위로 사용할 수 있고, 다른 클래스의 인스턴스들이 데이터를 공유하는 것이 가능해집니다.

단점

  • OCP(Open Closed Principal) 위배
  • 객체간 결합도가 높아지고, 유지 보수가 어렵고 테스트를 어렵게 합니다.
  • Muti-Thread 환경에서 동기화 처리가 되지 않은 경우, 인스턴스가 2개 생성되는 문제가 발생합니다.

방법

  1. Lazy Initialization
  2. Lazy Initialzation + Double-checked Locking -> Synchronized 성능 문제 때문에 권장 X
  3. Initialization on Demand holder idiom (Holder(클래스 안에 클래스를 두고, static final을 통해 클래스 로딩 시점에 한 번만 호출시키고, 값 재할당 방지) 적용)
public class ThreadSafe_Lazy_Initialization{
 
    private static ThreadSafe_Lazy_Initialization instance;
 
    private ThreadSafe_Lazy_Initialization(){
    }
     
    public static synchronized ThreadSafe_Lazy_Initialization getInstance(){
        if(instance == null){
            instance = new ThreadSafe_Lazy_Initialization();
        }
        return instance;
}


 public class ThreadSafe_Lazy_Initialization{
    
    private volatile static ThreadSafe_Lazy_Initialization instance;

    private ThreadSafe_Lazy_Initialization(){
    }

    public static ThreadSafe_Lazy_Initialization getInstance(){
    	if(instance == null) {
        	synchronized (ThreadSafe_Lazy_Initialization.class){
                if(instance == null){
                    instance = new ThreadSafe_Lazy_Initialization();
                }
            }
        }
        return instance;
    }
}

public class Something {
    
    private Something() {
    }
 
    private static class LazyHolder {
        public static final Something INSTANCE = new Something();
    }
 
    public static Something getInstance() {
        return LazyHolder.INSTANCE;
    }
}

 

일반적으로 3번 방식으로 holder를 두고 사용하는 것이 가장 성능적으로 뛰어나다고 합니다. 메모리 낭비를 방지할 수 있는 싱글톤 패턴과 적용 방식에 대해 알아보았고, 다음 포스팅으로는 템플릿 메서드 패턴에 대해 포스팅하도록 하겠습니다.