싱글톤 패턴

접근

  • 객체를 만들어 사용할 때 인스턴스가 2개 이상이면 프로그램에 이상이 생기는 경우가 발생할 수 있다.

  • 이러한 경우 특정 클래스에 객체 인스턴스를 하나만 만들 수 있도록 하는 패턴을 사용해야 한다.

  • 전역 변수를 사용하는 것과 같이 객체 인스턴스를 어디서든 접근할 수 있도록 하고, 해당 객체가 필요한 상황에 객체 인스턴스를 생성하면 된다.

    • 전역변수로 싱글톤 패턴을 구현할 경우, 언어마다 특징이 달라 외부 코드에서 덮어쓰여질 가능성이 있으므로 조심해서 사용해야 한다.

개념

  • 클래스 인스턴스를 하나만 만들고, 그 인스턴스로의 전역 접근을 제공하는 디자인 패턴이다.

  • 클래스 내부에서 하나뿐인 인스턴스를 관리한다. 다른 클래스에서 인스턴스 생성이 불가능하도록 막고, 클래스에 요청해야만 인스턴스를 얻을 수 있다.

장단점

  • 장점

    • 하나의 객체를 전역적으로 접근하는 것을 보장한다.

    • 초기화가 한 번만 이루어진다.

  • 단점

    • 싱글톤 객체는 사용하는 객체와 강하게 결합되어, 싱글톤 클래스에 변경이 발생했을 때 사용하는 쪽 클래스도 변경되어야 한다.

    • 객체 고유의 행동에 대한 책임, 객체를 싱글톤으로 유지하는 책임을 동시에 가지므로 단일 책임 원칙을 위반한다.

    • 테스트 코드 작성 시 Mock 객체를 사용하기 어렵다.

주의점

클래스로더

  • 클래스 로더가 여러 개라면 클래스 로더마다 서로 다른 네임스페이스를 정의하므로 같은 클래스를 여러 번 로딩할 수 있어 싱글톤 인스턴스가 여러 개 만들어질 수 있다. 따라서 클래스 로더가 여러 개인 상황이라면 주의해야 한다.

리플렉션, 직렬화/역직렬화

사용 방법

  • 외부에 노출되는 생성자가 없도록 모두 private 접근자로 둔다.

  • getInstance 정적 메서드에서 객체를 한 번만 생성하고, 생성된 객체를 필드에 저장해두어 재활용할 수 있도록 한다.

  • 멀티 스레드 환경에서 동시에 uniqueInstance가 존재하지 않을 때 getInstance 메서드에 접근하면 각기 다른 객체를 생성해 사용하게 되므로 문제가 발생한다.

  • 이를 해결하려면 아래 세 가지 방법 중 하나를 사용하면 된다.

    • getInstance 메서드에 synchrinozed 키워드를 붙여 동시에 여러 스레드에서 호출하지 못하게 한다.

    • 인스턴스를 클래스 초기화 시점에 생성하도록 한다.

    • DCL(Double-Checked Locking) 방식을 통해 객체 생성 전 인스턴스가 있는지 확인하고, synchronized 블록을 통해 싱글톤 클래스 자체에 락을 걸어 객체 생성을 동시에 수행되지 않도록 한다. 이를 통해 처음 객체를 생성할 때에만 동기화가 이뤄지도록 한다.

예시

  • Spring Session에서는 UUID를 비롯한 다양한 방식을 통해 세션 아이디를 생성할 수 있다.

  • 이 중 가장 기본적이고 널리 사용되는 UUID 방식으로 세션 아이디를 생성하도록 한 UuidSessionIdGenerator는 싱글톤으로 동작하도록 구현되었다.

  • Spring Cache에서는 Null 저장이 불가능한 캐시 솔루션을 다루기 위해 NullValue라는 클래스를 Null 대신 저장하도록 유도하고 있다. 여기서는 싱글톤 객체 필드에 직접 접근하도록 하고 있어 전역 변수처럼 사용하고 있다.

Last updated