본문 바로가기

Knowledge/Design Pattern

싱글톤 패턴 (Singleton Pattern)

싱글톤 패턴 (Singleton Pattern)


싱글톤 패턴은 해당 클래스의 인스턴스가 하나만 만들어지고, 어디서든지 그 인스턴스에 접근할 수 있도록 하기위한 패턴이다.


》》 단 하나의 유일한 객체를 만들기 위한 디자인 패턴


여기서 중요한 것은 인스턴스가 단 하나만 만들어지고, 어디서든지 접근가능하게 한다는 점이다 !

어디서 필요할까 ?

정의를 살펴보면 알 수 있듯이 프로그램 상에서 객체가 하나만 필요할 때 사용된다.

ex. 환경설정 관리 또는 로그관리, 동일한 DB커넥션 생성 → 여러 인스턴스가 존재할 필요가 없다!

싱글톤 패턴 대신 전역 변수에 객체를 대입해서 사용해도 되지 않을까?

전역 변수에 객체를 대입하면 프로그램이 시작될 때 객체가 생성된다그런데 만약 프로그램이 끝날때까지

그 객체를 한번도 쓰지 않는다면 자원만 낭비된다.

그렇다면 싱글톤 패턴은 어떻게 사용할까?

객체를 생성할 때 보통 new를 사용하여 객체를 생성하였다. 그러면 클래스에서 public 생성자가 호출되고 인스턴스가 생성되었다.



하지만 싱글톤 패턴이 적용된 클래스는 생성자 접근제어자가 private로 설정되어있다.



private접근제어자는 클래스내에서밖에 사용하질 못하는데 어떻게 외부에서 호출할까?


public class MyClass{

private static MyClass uniqueInstance;

private MyClass() {}

public static MyClass getInstance(){

if (uniqueInstance == null){

uniqueInstance = new MyClass();

}

return uniqueInstance;

}

}


싱글톤 패턴이 적용된 클래스의 내부를 보면 객체를 생성할 수 있는 정적메소드가 있다.

따라서 싱글톤 패턴 객체에 접근할 때는 다음과 같이 호출한다.


MyClass.getInstance();


하지만 이 코드에는 문제점이 있다.

문제점은 바로 이 클래스를 "멀티스레드"로 돌릴 시에 문제가 발생한다.

코드를 다시 한번 살펴보면...

코드에서 if(uniqueInstance == null) 줄을 (1) 번으로 생각하고 uniqueInstance = new MyClass() 줄을

(2) 번이라 생각해보자. 그리고 멀티스레드 즉, 스레드가 3개라고 가정을 해보자. (Thread = Work Flow)




그렇다면 코드를 어떻게 수정해야 할까?

싱글톤 패턴을 구현하는 방법에는 여러가지 방법이 제시된다.


Add synchronized keyword

이 방법은 getInstance()메소드에 synchronized 키워드만 추가해주는 방법이다. 한 스레드가 메소드 사용을
끝날 때까지 다른 스레드는 기다려야한다.

※ 하지만 동기화를 하면 속도 문제가 생기지 않을까?

사실 동기화가 꼭 필요한 시점은 이 메소드가 시작될 때 뿐이다. 처음 인스턴스가 생성되면 그 이후 과정은

불필요한 오버헤드만 증가할 뿐이다.


 더 효율적인 방법은 없을까?

인스턴스를 필요할 때 생성하지 말고, 처음부터 만들어버린다.


Eager initialization

프로그램에서 반드시 MyClass의 인스턴스가 사용하고, 그 인스턴스를 항상 사용한다면 인스턴스를 프로그램

시작과 동시에 초기화를 해줘도 된다.

하지만 이 방법에도 약간의 문제가 있는데 만약 프로그램의 크기가 커져서 수 많은 클래스에서 위와 같은

싱글톤 패턴을 이용한다고 가정해보자.


》》 프로그램 시작과 동시에 인스턴스를 생성하는데 부담

》》 클래스가 인스턴스화 되는 순간 어떠한 에러 처리를 하지 못함


Static block initialization
static 초기화 블록을 사용한다. 복잡한 초기변수 세팅이나 에러처리를 위한 구문을 담을 수 있다.


Initialization on demand holder idiom

클래스의 로드 시점을 이용하여 내부 클래스를 생성시킴으로 thread간의 동기화 문제를 해결한다.

미리 초기화하는 것은 앞서 나온 방법과 유사하지만 별도의 static class에서 초기화를 해서 가지고

있는것이 특이한점이다.

현재 자바에서 싱글톤 패턴을 사용한다고하면 거의 이 방법을 사용한다고 볼 수 있다.


DCL (Double Checking Locking)

일단 인스턴스가 생성되있는지 확인하고 생성되어있지 않았을때만 동기화한다처음에만 동기화하고

나중에는 동기화를 하지 않아도 된다.


Enum initialization

자바의 enum값이 프로그램내에서 오직 한번만 인스턴스화 되는점을 이용한다.

enum값은 전역적으로 접근이 가능하다사용이 간편하고, 멀티스레드로부터 안전하다.

많이 알려지지 않았지만 자바 언어에서 보장하는 좋은 방법이다.


이처럼 싱글톤 패턴을 구현하는데 다양한 방법들이 존재한다.


싱글톤 패턴은 4대 디자인 패턴에 들어갈 정도로 흔히 쓰이는 패턴으로 가장 쉬우면서도 가장 문제가 될 소지를

가지는 패턴이라고 볼 수 있다.