HomeAboutMeBlogGuest
© 2025 Sejin Cha. All rights reserved.
Built with Next.js, deployed on Vercel
📝
남득윤 학습 저장소
/
객체 지향 프로그래밍
객체 지향 프로그래밍
/
디자인 패턴
디자인 패턴
/
1️⃣
Singleton Pattern
1️⃣

Singleton Pattern

💡
싱글턴(singletone)이란 인스턴스를 오직 하나만 생성할 수 있는 클래스를 말한다.[Gamma95]

Motivation

클래스별로 유일한 인스턴스를 보장하는 것이 중요한 경우가 있다. 싱글톤은 리소스의 관리를 중앙화해서 access point를 딱 하나만 제공하는 역할을 한다.
싱글톤 패턴은 가장 간단한 디자인 패턴중 하나이다.
퍼블릭 생성자를 막자. 그리고 딱하나만 만들고 그것을 주면된다.

Intent

  • 인스턴스를 딱하나만 만들기
  • global access point를 딱하나만 제공하기
 

Implementation

싱글톤을 구현하는 가장 간단한 방법
1. 생성자를 private으로 감추기 2. public static 멤버를 통해 딱하나만 생성한 인스턴스 제공하기
// Thread Unsafe, Lazy Initilization class Singleton { private static Singleton instance; private Singleton() { ... } public static Singleton getInstance(){ if (instance == null) instance = new Singleton(); return instance; } ... public void doSomething() { ... }

Examples

  • 로거 클래스
  • 설정 클래스
  • 팩토리 클래스
  • java.lang.Runtime#getRuntime()
  • java.lang.System#getSecurityManager()

Specific Issues

Thread-safe implementation
  • Early instantiation using implementation with static field
//Early instantiation using implementation with static field. class Singleton { private static final Singleton instance = new Singleton(); private Singleton(){} public static Singleton getInstance(){ return instance; } }
  • Lazy instantiation using double chekced locking mechanism.
//Lazy instantiation using double chekced locking mechanism. class Singleton { private static volatile Singleton instance; //자바 1.4이하의 메모리 관리 기술도 이해해야함 private Singleton(){ } public static Singleton getInstance(){ if (instance == null) { synchronized(Singleton.class) { if (instance == null) { instance = new Singleton(); } } } return instance; } }
 
Protected constructor
간단히 싱글톤으로 만들려면 private 생성자를 쓰면된다.
근데 private 생성자만 쓰면 상속을 할 수 없다. 그렇다고 public을 쓰면 싱글톤을 보장 할 수 없다.
그래서 절충안으로 protected 생성자를 쓰게되면 한가지 단점이 있다.
  1. 같은 패키지에서 생성자 호출 가능 → 싱글톤 만을위한 패키지를 만들어 해결 가능
 
Serialization
싱글턴 클래스를 직렬화하려면 Serializable을 구현한다고 선언하는 것만으로는 부족하다.
  • 모든 인스턴스 필드를 일시적 (transient)라고 선언하고
  • readResolve 메서드를 제공해야 한다.
 
이렇게 하지 않으면 직렬화된 인스턴스를 역직렬화할 때마다 새로운 인스턴스가 생성된다.
 
Reflection 공격
  • 권한이 있는 사용자는 AccessibleObject.setAccesible을 사용해 private 생성자를 호출할 수 있음
  • 생성자를 수정해서 두번 째 객체가 생성되려 할 때 예외를 던지게 하여 방어 할 수 있음
 
Stateless
  • 특정 클라이언트에 의존적인 필드가 있으면 안된다.
  • 특정 클라이언트가 값을 변경할 수 있는 필드가 있으면 안된다!
  • 가급적 읽기만 가능해야 한다.
  • 필드 대신에 자바에서 공유되지 않는, 지역변수, 파라미터, ThreadLocal 등을 사용해야 한다.

인스턴스 제공 멤버로 필드 vs 메서드

필드

  • 명확하다.
  • 간결하다.

메서드

  • API의 변경없이 생성 정책을 변경할 수 있다.
    • e.g.) 완전 싱글턴 → 쓰레드별로 인스턴스 제공 (see also - ThreadLocal)
  • static factory method → generic singletone factory로 변경가능
  • Method Reference 활용 가능
    • e.g.) Elvis::getinstance 를 Supplier<Elvis>로 활용
 
 

세 번째 방법은 원소가 하나인 열거 타입을 선언하는 것

public enum Elvis { INSTANCE; }
  • 더 간결함
  • 직렬화, 리플렉션 관련 이슈 없음
  • 대상 싱글턴 객체가 Enum 외의 클래스를 상속해야하는 경우 사용할 수 없음
  • 대부분의 상황에서는 가장 좋은 방법이다.
 

네 번째 방법은 static inner 클래스 사용하기

(Bill Pugh Solution)
//inner static class 활용 class Singleton { private Singleton() {} private static class SingletonHolder { private static final Singleton INSTANCE = new Singleton(); } public static Singleton getInstance() { return SingletonHolder.Instance; } }
 
Reference)
refactoring-guru - Singleton
oodesign.com - Singleton
JournalDev - Java Singleton Design Pattern Best Practices with Examples
이펙티브 자바 Effective Java 3/E
  • 아이템 3. private 생성자나 열거 타입으로 싱글턴임을 보증하라
백기선 - [GoF 디자인 패턴]
  • 싱글톤 패턴 1부, 싱글톤 패턴 제일 간단히 구현하는 방법?
  • 싱글톤 패턴 2부, 멀티쓰레드 환경에서 안전하게 구현하는 방법.
 
See Also)
싱글톤 레지스트리 (e.g.스프링 컨테이너, @Configuration@Bean→ DI, IOC)
[10분 테코톡] 🧇 크로플의 싱글턴과 정적클래스