Java에서의 Singleton 패턴



1. Singleton 패턴이란?

  • 싱글톤 패턴(Singleton Pattern)은 단 하나의 객체만 생성해야 할 때 사용하는 디자인 패턴입니다.
  • 이 패턴을 적용하면 애플리케이션 내에서 여러 곳에서 동일한 인스턴스를 참조할 수 있으며, 프로그램 전반에서 하나의 객체를 전역적으로 관리할 수 있습니다.

1) 싱글톤 패턴의 핵심 개념

(1) 하나의 객체만 생성됨

  • 싱글톤 패턴은 프로그램이 실행되는 동안 딱 하나의 객체만 생성되며, 이 객체는 프로그램 어디서든 동일하게 사용됩니다.

(2) private 생성자 사용

  • 외부에서 new 연산자를 사용하여 새로운 객체를 생성하지 못하도록, 생성자를 private으로 설정합니다. 이렇게 함으로써 외부에서는 객체를 직접 생성하지 못하고, 제공되는 메서드를 통해서만 객체에 접근할 수 있습니다.

(3) 정적 메서드를 통한 객체 반환

  • 객체는 정적 메서드를 통해서만 접근할 수 있으며, 이 메서드를 호출하면 단 하나의 인스턴스를 반환합니다.


2. Singleton 패턴의 필요성

  • 싱글톤 패턴은 여러 곳에서 동일한 객체를 사용할 때 유용합니다.
  • 이러한 상황에서는 불필요한 객체 생성을 피하고 자원 절약과 일관성 유지를 위해 싱글톤 패턴이 필요합니다.

1) 환경 설정 객체: 애플리케이션 전역에서 동일한 설정 값을 참조해야 할 때.

2) 로그 관리자: 프로그램 전반에서 동일한 로그 시스템을 사용할 때.

3) 데이터베이스 연결 관리: 여러 곳에서 동일한 데이터베이스 연결 객체를 사용해야 할 때.

이처럼 하나의 객체만 유지되어야 할 때, 싱글톤 패턴을 사용하면 불필요한 객체 생성을 방지하고 자원을 절약할 수 있습니다.


3. Singleton 패턴 구현

package _05_class._access_modifier._pack5;

public class Singleton {
    // 클래스가 로드될 때 단 한 번 초기화되는 정적 필드를 선언
    private static Singleton singleton = new Singleton();

    // 외부에서 new로 객체를 생성할 수 없도록 private 생성자 선언
    private Singleton() {}

    // 싱글톤 객체에 접근할 수 있는 public 정적 메서드 제공
    public static Singleton getInstance() {
        return singleton;
    }
}

1) 구현 설명

(1) 정적 필드 (static field)

  • private static Singleton singleton = new Singleton();는 정적 필드로 선언되어 클래스가 로드될 때 단 한 번 초기화됩니다. 이는 프로그램이 실행되는 동안 오직 하나의 객체만 생성되도록 보장합니다.

(2) private 생성자

  • private Singleton() 생성자는 외부에서 객체를 직접 생성하지 못하도록 설계되었습니다. 이렇게 설정함으로써 다른 클래스에서 new Singleton()을 통해 객체를 생성할 수 없으며, 이를 통해 단일 인스턴스를 유지합니다.

(3) 정적 메서드 (static method)

  • public static Singleton getInstance()는 싱글톤 객체에 접근할 수 있는 유일한 방법입니다. 이 메서드는 항상 동일한 singleton 객체를 반환하며, 외부에서 객체를 생성하는 것이 아니라 이미 생성된 객체에 접근할 수 있습니다.


4. Singleton 패턴 사용 예시

싱글톤 패턴을 사용하여 객체가 하나만 생성되는지 확인해보는 코드입니다.

package _05_class._access_modifier._pack5;

public class SingletonEx {
    public static void main(String[] args) {
        // Singleton s1 = new Singleton();
        // 컴파일 에러 발생: private 생성자 때문에 외부에서 new로 객체 생성 불가

        // 정적 메서드를 통해 싱글톤 객체를 얻음
        Singleton s2 = Singleton.getInstance();
        Singleton s3 = Singleton.getInstance();

        // 동일한 객체를 참조하는지 확인 (s2와 s3는 동일한 객체)
        if (s2 == s3) {
            System.out.println("같은 Singleton 객체");
            System.out.println(s2);
            System.out.println(s3);
        } else {
            System.out.println("다른 Singleton 객체");
        }
    }
}

1) 예시 코드 설명

(1) 객체 참조 비교

  • Singleton.getInstance() 메서드를 사용하여 두 개의 변수 s2s3에 객체를 할당합니다. 싱글톤 패턴에 의해 하나의 객체만 생성되므로, s2s3는 동일한 객체를 참조합니다.

(2) 참조 동일성 검사

  • s2 == s3 조건을 사용해 두 변수가 동일한 객체를 참조하는지 확인합니다. 조건이 참이라면 s2s3는 동일한 인스턴스를 가리키고 있다는 의미입니다. 따라서 출력 결과는 “같은 Singleton 객체”가 됩니다.

출력 결과

같은 Singleton 객체
_05_class._access_modifier._pack5.Singleton@1a2b3c4d
_05_class._access_modifier._pack5.Singleton@1a2b3c4d

두 객체의 참조 주소가 동일함을 확인할 수 있습니다. 즉, s2s3는 모두 같은 인스턴스를 가리키고 있습니다.


5. Singleton 패턴의 장단점

1) 장점

(1) 자원 절약

  • 객체를 한 번만 생성하므로 메모리 자원을 절약할 수 있습니다. 특히 객체 생성 비용이 높은 경우 싱글톤 패턴을 통해 성능 향상을 기대할 수 있습니다.

(2) 전역 접근 가능

  • 싱글톤 객체는 전역적으로 접근 가능하여, 여러 클래스에서 동일한 객체를 공유하고 사용할 수 있습니다. 이를 통해 애플리케이션 내에서 일관된 상태를 유지할 수 있습니다.

(3) 상태 관리 용이

  • 하나의 인스턴스만 존재하므로, 애플리케이션 전체에서 동일한 상태를 유지할 수 있습니다. 이로 인해 데이터 일관성이 유지됩니다.

2) 단점

(1) 테스트 어려움

  • 싱글톤 패턴은 객체의 상태가 전역적으로 공유되므로, 테스트 시 독립적으로 객체를 관리하기 어렵습니다. 각 테스트마다 객체의 상태를 초기화하거나 분리된 인스턴스를 사용하는 것이 불가능할 수 있습니다.

(2) 멀티스레드 환경에서의 문제

  • 멀티스레드 환경에서 동기화 처리가 되어 있지 않으면, 여러 스레드가 동시에 객체를 생성하려고 시도할 수 있어 문제가 발생할 수 있습니다. 이를 방지하려면 싱글톤 패턴을 Thread-safe하게 구현해야 합니다.