본문 바로가기

Design/Design Pattern

[Design Pattern] Singleton Pattern

이번 장에서는 싱클톤(Singleton) 패턴에 대해서 알아보도록 한다.
샘플 코드는 여기 (링크) 프로젝트의 테스트 코드로 정리해두었다.


이번 싱글톤 패턴은 "데이터베이스" 클라이언트를 생성하고 생성된 객체를 재사용하는 과정을 통해 살펴보도록 한다.

싱글톤 패턴이란?

하나의 어플리케이션에서 단 하나의 인스턴스만 생성하서 사용하는 디자인 패턴이다.
고정된 메모리 영역을 사용하면서 한번의 생성으로 인스턴스 사용을 공유하기 때문에 메모리 낭비를 방지할 수 있다.

필자가 작성한 다른 디자인 패턴 글과는 다르게 이번에는 싱글톤 패턴의 단점을 보완하는 방법에 대해서 알아본다.
OCP 위반등 여러가지 단점이 있지만 이번에 다룰 단점은 Multi Thread 환경에서 복수의 인스턴스가 생성될 수 있다는 점을 해결하는 방법에 대해서 알아본다.


Thread Safe하지 못한 방식

ThreadNonSafeMariaClient
다중 Thread의 접근에 대한 처리가 되어있지 않은 MariaDB Client 클래스다.
단일 Thread에서만 작동한다면 아래의 코드는 전혀 문제가 되지 않는다.
그림에서 확인되는 것 처럼 Client를 객체화하는데 100ms가 소요된다.
100ms 동안에는 여전히 THREAD_NON_SAFE_MARIA_CLIENT = null인 상태이다.
이러한 상태에서 다른 Thread에서 getInstance를 호출하게 된다면 동시에 여러개의 인스턴스가 생성되며 우리가 기대한 것과는 다르게 작동할 것이다.

UserThread
Thread를 확장하고 있으며 ThreadNonSafeMariaClient에게 인스턴스를 요청하는 작업을 한다.

User
UserThread를 생성하고 병렬로 실행시키는 클라이언트 클래스.
코드 마지막에 Thread를 1초 중지하는 코드는 다른 Thread가 작업을 완료하기 전에
테스트를 진행하는 Thread가 종료되는 것을 방지하기 위한 코드이므로 무시해도 좋다.

코드를 실행한 결과는 아래와 같다.

우리의 기대와는 다르게 총 다섯 개의 인스턴스가 생성되었다.
Thread Safe하지 못하기 때문이다.


Thread Safe한 방식

ThreadSafeMariaClient
ThreadNonSafeMariaClient와 다르게 getInstance에 synchronized를 붙였고 여러 Thread가 동시에 접근하지 못하도록 수정하였다.

UserThread
ThreadSafeMariaClient에게 인스턴스를 요청하도록 수정하였다.

코드를 실행한 결과는 아래와 같다.

우리가 기대한 것과 같이 단 하나의 인스턴스만 생성되었다.

Thread Safe하게 하는 방식은 여러가지가 있다.
synchronized를 사용하는 경우 Thread간의 경합으로 성능 이슈가 발생할 수 있다.
이러한 경우 JVM에 클래스 로딩되는 시점에 인스턴스를 초기화하는 방법도 있다.

이렇게 되는 경우에도 우리의 기대와 같이 단 하나의 인스턴스만 사용하게 되는 것을 알 수 있다.


지금까지 싱글톤 패턴을 DB 클라이언트 클래스로 예를들어서 알아보았다.