본문 바로가기
기초 CS 정리

싱글턴 패턴

by 쿠리의일상 2023. 3. 12.
애플리케이션이 시작될 때 어떤 클래스가 최초 1번만 메모리를 할당하고 해당 메모리에 인스턴스를 만들어서 사용하는 패턴

 

즉, 싱클톤 패턴은 하나의 인스턴스만 생성하여 사용하는 디자인 패턴, 인스턴스가 필요하면 똑같은 인스턴스를 만들지 않고 기존에 있는 인스턴스를 활용하는 것

 

생성자가 여러 번 호출되도 실제로 생성되는 객체는 하나이며 최초로 생성된 이후에 호출된 생성자는 이미 생성한 객체를 반환시키도록 만든다.

→ 생성자를 private으로 선언하여 다른 곳에서 생성하지 못하도록 만들고 getInstance() 메서드를 통해 받아서 사용하도록 구현해준다.

 

 


  • 객체를 생성할 때마다 메모리 영역을 할당 받아야 한다. 하지만 한번의 new를 통해 객체를 생성해준다면 메모리 낭비를 방지할 수 있고 싱글톤으로 구현한 인스턴스는 전역이므로 다른 클래스의 인스턴스들이 데이터를 공유하는 것이 가능하다.
  • 공통된 객체를 여러 개 생성해서 사용해야하는 상황 → 데이터베이스에서 커넥션풀, 스레드풀, 캐시, 로그 기록 객체 등
  • 안드로이드 앱에서 각 액티비티 들이나 클래스마다 주요 클래스들을 하나하나 전달하는게 번거롭기에 싱글톤 클래스를 만들어 어디서든 접근하도록 설계

 

  • 다만, 객체 지향 설계 원칙 중 개방 폐쇄 원칙에 위배될 가능성이 크다.
  • 싱글톤 인스턴스가 혼자 너무 많은 일을 하거나 많은 데이터를 공유시키면 다른 클래스들 간의 결합도가 높아질 가능성이 크다.
  • 결합도가 높아지면 유지보수가 힘들고 테스트도 원활하게 진행할 수 없다.
  • 멀티 스레드 환경에서 동기화 처리를 하지 않았을 때 인스턴스가 2개 생성되는 문제도 발생할 수 있으며 반드시 싱글톤이 필요한 상황이 아니면 지양하는 것이 좋다고 한다.

 

멀티 스레드 환경에서 안전한 싱글톤을 만드는 법

//1 초기화 지연
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_Initializtion();
		}
		return instance;
	}
}
  1. private static 으로 인스턴스 변수를 만들고
  2. private 로 생성자를 만들어서 외부에서 생성을 막는다
  3. 그리고 synchronized 동기화를 활용하여 스레드를 안전하게 만든다 → 다만 synchronized를 사용하면 큰 성능저하를 발생시키므로 지양

 

//2 초기화 지연+더블 락 체크
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;
	}
}
  1. private static으로 인스턴스 변수를 만들고
  2. private 생성자를 만들어서 외부에서 생성을 막고
  3. getInstance() 메서드에서 일차적으로 인스턴스의 존재 여부를 확인하고 synchronized를 통하여 동기화를 시켜 인스턴스를 생성하는 방법

스레드를 안전하게 만들면서 처음 생성 이후 synchronized를 실행하지 않기에 성능 저하 완화가 가능

 

 

 

//3 holder에 의한 초기화 -> 가장 많이 사용되는 일반적 싱글톤 클래스 사용법
public class Something {
	private Something() { }
	private static class LazyHolder {
		public static final Something INSTANCE = new Something();
	}

	public static Something getInstance () {
		return LazyHolder.INSTANCE;
	}
}

동기화를 사용하지 않는 이유는 개발자가 직접 동기화에 대한 코드를 작성하면서 회피하려고 하면 프로그램 구조가 그만큼 복잡해지고 비용 문제가 발생할 수 있기에 JVM의 클래스 초기화 과정에서 보장되는 원자적 특성을 사용하여 싱글톤의 초기화 문제에 대한 책임을 JVM에게 떠넘기는 걸 활용한다.

클래스 안에 선언한 클래스인 LazyHolder에서 선언된 인스턴스는 static이므로 클래스 로딩 시점에서 한번만 호출되고 final을 통해 다시 값이 할당되지 않도록 만드는 방식을 사용

 

'기초 CS 정리' 카테고리의 다른 글

PostCSS 란  (0) 2023.08.05
오픈API 사용하여 웹 사이트 만들기  (0) 2023.05.04
디자인 패턴 - 어댑터 패턴  (0) 2023.03.05
JWT (Json Web Token)  (0) 2023.02.26
OAuth (Open Authorization)  (0) 2023.02.25