티스토리 뷰

싱글턴( Singleton ) 패턴


오직 단 한개의 Instance만 제공하는 클래스

 

Non Thread-Safe Singleton

 

생성방법
  • private constructor 를 통해 외부에서 new 키워드를 통해 인스턴스 생성을 할 수 없도록 막는다.
  • 내부에서 단 하나의 인스턴스를 생성하고 메소드로 외부에 제공한다.

다만 이와 같은 방법은 getInstance() 는 단일 연산이 아니기 때문에 동시에 많은 쓰레드가 접근 하였을 때, 여러 개의 인스턴스가 생성될 수 있다. 따라서 아래와 같은 방법을 제공한다.

 

 

Thread Safe Singleton

 

Eager Initialization Singleton

  • Eager Initialization( 이른 초기화 ) 방식을 통한 Singleton Object 생성방식이다. 애플리케이션이 실행되는 시점에 미리 객체를 생성해 Thread-Safe 하다.
    • But. 미리 객체를 생성해 두기 때문에 많은 메모리를 잡아먹을 수 있다.

 

Locking Singleton

  • syncronized 를 사용하여 getInstance() 메소드에 한 번에 단 하나의 스레드만 접근 가능하도록 락을 걸어 다 수의 인스턴스 생성 문제를 피할 수 있다.

다만 위와 같은 방법은 메서드 전 영역에 Lock 을 걸고 있기 때문에, 동시에 해당 메서드에서 처리할 수 있는 쓰레드의 수가 줄어든다고 볼 수 있다. 이는 성능적 문제를 야기할 수 있다. 

 

 

Double Checked Locking Singleton

  • Double Checked Locking 의 방식은 인스턴스 첫 생성에 있어서 첫번째   if 문 을 통과한 여러 스레드들은 두번째 if 를 통해 단 하나의 인스턴스만 생성하고. 그 이후 해당 메서드를 호출하는 모든 인스턴스들은 첫 번째  if 문  에 의해 동기화 블럭에 접근하지 않기 때문에 성능적 이슈도 해결하고, 늦은 초기화 (lazy initialization)도 가능하다.

 

반드시   volatile  키워드가 필요한 이유
  • 최초에 싱글톤 생성시에 첫번째 if(instance == null) 을 통과한 스레드가 2개 이상일 때 동기화 블럭 내에서 인스턴스 생성 후 바로 메모리에 써지지 않고 CPU에 레지스트리에 저장된 경우 두번째 스레드 역시 인스턴스를 생성하게 되는 상황이 있을 수 있다. 때문에 volatile 키워드로 바로 메모리에 객체가 생성될 수 있도록 해야 Thread-safe한 싱글톤 객체가 될 수 있다.

  1. 변수 a를 코어로 이동한다
  2. 변수 a+1을 해준다.
  3. +1 된 변수 a는 효율적인 데이터처리를 위해 레지스터에 버퍼링된다.
  4. 다른 쓰레드에 의해 변수 a가 코어로 이동한다. (이 때 변수 a+1의 결과값이 다른 코어에 버퍼링되어 있어 적용되지 않은 상태이다)
  5. 변수 a+1을 해준다.
  6. 2 번의 결과값이 메모리에 쓰여진다
  7. 5 번의 결과값이 메모리에 쓰여진다
💡 2번의 +1 작업이 있었음에도 불구하고 메모리에는 +2가 아닌 +1된 a의 값이 저장되어 있다. 이를 방지하기 위한 자바의 키워드가 volatile 인데 해당 키워드가 붙어있는 변수는 CPU에서 작업이 끝나고 레지스터에 버퍼링되지 않고 바로 메모리에 Write된다.

 

Inner Static Class  Singleton

위와 같이 Inner Static Class 를 사용한 방식 역시 지연 초기화 및 싱글턴을 보장할 수 있다. 기본적으로 static filed 는 해당 필드를 포함한 클래스를 처음 클래스 로더가 읽어들일 때 메모리에 생성하게 되는데. 현재 HoldergetInstance 호출 이외에 어떤 방법으로도 접근할 수 없도록 차단되어 있기 때문에 getInstance 를 호출했을 대 최초로 인스턴스가 초기화되며 그 이후 요청 부터는 이전에 생성 되었던 필드를 재활용하기 때문에 싱글턴을 유지할 수 있다.

 

싱글턴 클래스의 인스턴스 2개이상 생성하는 방법

 

리플렉션(Reflection) 사용하기

사용 싱글톤 객체는 Inner Static Class 방식으로 만들어진 Singleton Object

 

 

직렬화 역직렬화 사용하기

직렬화 하기 위해서는 Serializable 마커인터페이스가 필요하다.

직렬화•역직렬화 하기

 

💡 직렬화•역직렬화에도 단 하나의 인스턴스만 생성하는 방법

 

절대 한 개만 생성되는 Enum 으로 생성한 Sigleton 오브젝트

  • ENUM(열거형) 을 사용해 생성한 Instance는 싱글턴이다.
    • 다만 내부적으로 Enum 클래스의 상속을 받고 있기 때문에 상속을 사용할 수 없고, 지연 초기화 방식이 아니라는 단점이 있다.
  • ENUM 타입에는 리플렉션을 사용할 수 없다.

 

 

예제 코드

 

참조

 

코딩으로 학습하는 GoF의 디자인 패턴 - 인프런 | 강의

디자인 패턴을 알고 있다면 스프링 뿐 아니라 여러 다양한 기술 및 프로그래밍 언어도 보다 쉽게 학습할 수 있습니다. 또한, 보다 유연하고 재사용성이 뛰어난 객체 지향 소프트웨어를 개발할

www.inflearn.com

댓글