본문 바로가기
공부/JAVA

[디자인패턴] 싱글톤(Singleton)

by 밍미 2018. 11. 19.
singleton

Design Pattern

디자인 패턴은 프로그램 개발에서 자주 발생하는 문제를 해결하기 위한 방법 중 하나로, 특정 디자인 규약을 설계 시 간편하게 재사용해서 적용할 수 있도록 패턴화한 솔루션이다.

이러한 디자인 패턴의 종류는 아주 다양한데, 전부는 어렵더라도 시간날 때마다 하나씩 천천히 정리해나가보려고 한다.

뭐니뭐니해도 디자인 패턴 중 가장 유명한 패턴은 싱글톤 패턴이 아닐까 해서 오늘은 싱글톤 패턴을 정리해볼 것이다.

 

 

Singleton

싱글턴 패턴(Singleton pattern)을 따르는 클래스는, 생성자가 여러 차례 호출되더라도 실제로 생성되는 객체는 하나이고 최초 생성 이후에 호출된 생성자는 최초의 생성자가 생성한 객체를 리턴한다.

[출처] 위키백과

이렇게 보면 뭔가 말이 좀 어려운데.. 나름 풀어서 써보자면 Connection pool이나 logger처럼 전체 코드에서 하나만 존재해야 하는 객체가 있을 때, 객체의 인스턴스를 최초로 생성한 후에는 다른 클래스에서 새로 생성할 수 없도록 막고 기존에 생성된 인스턴스를 호출해서 사용하도록 하는 것이다.

 

 

Singleton 구현 방법

  • 기본 구현 방법

    • 싱글톤의 인스턴스를 static으로 선언해서 정적 객체로 생성한다. 하지만 private 접근제어자가 붙었기 때문에 직접적으로 접근할 수 없다.
    • 클래스 로딩 시에 객체를 생성하므로 인스턴스가 중복 생성되지 않는다.
    • 생성자 또한 private로 선언해서 다른 클래스에서 new연산자를 이용해 새로운 인스턴스를 생성할 수 없도록 막는다.
    • 외부 클래스에서는 public static으로 선언된 인스턴스 호출 메서드인 getInstane()만 접근 가능하다.
    • 싱글톤 객체를 사용하지 않아도 클래스 로딩 시에 객체가 생성되어 메모리를 사용하기 때문에 비효율적일 수 있다.

 

  • 게으른 인스턴스 생성(Lazy instantation) 방법

    • 인스턴스를 미리 생성해놓지않고, 필요할 때 getInstance() 메서드를 사용할 때 인스턴스를 생성한다.
    • 싱글톤 객체를 자주 사용하지 않을 경우 자원을 아낄 수 있다.
    • 멀티스레드 환경에서 여러 스레드가 동시에 메서드를 호출할 경우 인스턴스가 중복 생성될 수도 있다.

 

  • synchronized를 이용한 방법

    • synchronized로 메서드를 선언함으로써 멀티스레드 환경에서 중복 생성을 방지할 수 있다. (메서드가 동기화 되어 한 번에 여러 스레드가 메서드를 호출할 수 없음)
    • 많은 스레드가 동시에 메서드에 접근할 경우, 애플리케이션의 전반적인 속도가 급격하게 저하될 수 있다.

 

  • DCL(Double-Checking Locking) 기법

    • 인스턴스가 생성되어있는지 확인 후, 최초 접근에 대해서만 동기화를 해 인스턴스를 생성한다.

    • 자바 버전 1.5 이상에서만 적용 가능하다.

    • 그럴듯하게 보이지만, 멀티스레드 환경에서 두개의 스레드가 동시에 getInstance()를 호출한다고 생각해보자. (참고)

      • T1 -> getInstance() -> singleton == null -> synchronized 블록 진입
      • T1 -> 생성자 호출 전 non-null 인스턴스 생성
      • T2 -> getInstance() -> singleton != null -> T1에 의해 부분적으로 초기화된 인스턴스 리턴
      • T1 -> new Singleton()으로 Singleton 객체를 초기화하고 인스턴스를 리턴
      • T2가 리턴하는 인스턴스는 메모리만 할당되었을 뿐, 초기화가 완료되지 않은 상태의 객체이기 때문에 이 방법이 안정성을 보장한다고 할 수 없다.

 

  • LazyHolder 기법 (Initialization on demand holder idiom)

    • 중첩 클래스인 LazyHolder 클래스는 getInstance() 메서드에서 호출하기 전에는 로딩되지 않는다. 메서드 호출과 동시에 class가 로딩되면서 생성된 인스턴스가 리턴된다.
    • 인스턴스는 정적상수이므로 중복 생성되지 않는다.
    • 스레드 간 동기화 문제도 없으며, 모든 자바버전에서 사용 가능하다.

 

  • Enum을 사용한 방법

    • 모든 Enum 타입의 인스턴스는 클래스 로딩 시점에 한 번만 생성된다.
    • INSTANCE 생성 시 멀티 스레드로부터 안전하다. (Thread-safety)
    • 프로그램 전역에서 접근 가능하다.

'공부 > JAVA' 카테고리의 다른 글

[디자인패턴] 템플릿 메서드 패턴(Template Method Pattern)  (0) 2019.01.04
[Thread] 동기화와 교착상태  (0) 2018.06.11
[Thread] Thread  (0) 2018.06.11
[자료구조] 비선형구조  (0) 2018.06.08
[자료구조] 선형구조  (0) 2018.06.05

댓글