자바의 싱글 톤

1. 소개

이 빠른 기사에서는 일반 Java에서 싱글 톤을 구현하는 가장 널리 사용되는 두 가지 방법에 대해 설명합니다.

2. 클래스 기반 싱글 톤

가장 널리 사용되는 접근 방식은 일반 클래스를 만들고 다음이 있는지 확인하여 Singleton을 구현하는 것입니다.

  • 개인 생성자
  • 유일한 인스턴스를 포함하는 정적 필드
  • 인스턴스를 얻기위한 정적 팩토리 메소드

나중에 사용하기 위해 info 속성도 추가합니다. 따라서 구현은 다음과 같습니다.

public final class ClassSingleton { private static ClassSingleton INSTANCE; private String info = "Initial info class"; private ClassSingleton() { } public static ClassSingleton getInstance() { if(INSTANCE == null) { INSTANCE = new ClassSingleton(); } return INSTANCE; } // getters and setters }

이것이 일반적인 접근 방식이지만 멀티 스레딩 시나리오에서 문제가 될 수 있다는 점에 유의해야합니다. 이것이 Singleton을 사용하는 주된 이유입니다.

간단히 말해서, 하나 이상의 인스턴스가 생성되어 패턴의 핵심 원칙을 위반할 수 있습니다. 이 문제에 대한 잠금 솔루션이 있지만 다음 접근 방식은 이러한 문제를 루트 수준에서 해결합니다.

3. 열거 형 싱글 톤

계속해서 열거를 사용하는 또 다른 흥미로운 접근 방식에 대해 논의하지 않겠습니다.

public enum EnumSingleton { INSTANCE("Initial class info"); private String info; private EnumSingleton(String info) { this.info = info; } public EnumSingleton getInstance() { return INSTANCE; } // getters and setters }

이 접근 방식에는 열거 형 구현 자체에 의해 보장되는 직렬화 및 스레드 안전성이있어 내부적으로 단일 인스턴스 만 사용할 수 있도록 보장하여 클래스 기반 구현에서 지적 된 문제를 수정합니다.

4. 사용법

ClassSingleton 을 사용하려면 인스턴스를 정적으로 가져 오기만 하면됩니다.

ClassSingleton classSingleton1 = ClassSingleton.getInstance(); System.out.println(classSingleton1.getInfo()); //Initial class info ClassSingleton classSingleton2 = ClassSingleton.getInstance(); classSingleton2.setInfo("New class info"); System.out.println(classSingleton1.getInfo()); //New class info System.out.println(classSingleton2.getInfo()); //New class info

에 관해서는 EnumSingleton , 우리는 다른 Java 열거처럼 사용할 수 있습니다 :

EnumSingleton enumSingleton1 = EnumSingleton.INSTANCE.getInstance(); System.out.println(enumSingleton1.getInfo()); //Initial enum info EnumSingleton enumSingleton2 = EnumSingleton.INSTANCE.getInstance(); enumSingleton2.setInfo("New enum info"); System.out.println(enumSingleton1.getInfo()); // New enum info System.out.println(enumSingleton2.getInfo()); // New enum info

5. 일반적인 함정

싱글 톤은 믿을 수 없을 정도로 단순한 디자인 패턴이며 프로그래머가 싱글 톤을 만들 때 범할 수있는 일반적인 실수는 거의 없습니다.

싱글 톤으로 두 가지 유형의 문제를 구분합니다.

  • 실존 적 (싱글 톤이 필요합니까?)
  • 구현 적 (올바르게 구현합니까?)

5.1. 존재하는 문제

개념적으로 싱글 톤은 일종의 전역 변수입니다. 일반적으로 전역 변수는 피해야한다는 것을 알고 있습니다. 특히 상태가 변경 가능한 경우에는 더욱 그렇습니다.

싱글 톤을 사용해서는 안된다는 말이 아닙니다. 그러나 우리는 코드를 구성하는보다 효율적인 방법이있을 수 있다고 말하고 있습니다.

메서드의 구현이 싱글 톤 객체에 의존하는 경우 매개 변수로 전달하지 않는 이유는 무엇입니까? 이 경우 메서드가 의존하는 것을 명시 적으로 보여줍니다. 결과적으로 테스트를 수행 할 때 필요한 경우 이러한 종속성을 쉽게 조롱 할 수 있습니다.

예를 들어, 싱글 톤은 종종 애플리케이션의 구성 데이터 (예 : 저장소에 대한 연결)를 포함하는 데 사용됩니다. 전역 개체로 사용하면 테스트 환경에 대한 구성을 선택하기가 어려워집니다.

따라서 테스트를 실행할 때 프로덕션 데이터베이스가 테스트 데이터로 손상되어 거의 허용되지 않습니다.

싱글 톤이 필요하면 인스턴스화를 다른 클래스 (팩토리 같은)로 위임 할 가능성을 고려할 수 있습니다.이 인스턴스는 단일 인스턴스의 인스턴스가 하나만 존재하는지 확인해야합니다.

5.2. 구현 문제

싱글 톤은 매우 단순 해 보이지만 구현에는 다양한 문제가있을 수 있습니다. 모두 결과적으로 클래스의 인스턴스가 하나 이상이 될 수 있습니다.

동기화

위에서 제시 한 개인 생성자를 사용한 구현은 스레드로부터 안전하지 않습니다. 단일 스레드 환경에서는 잘 작동하지만 다중 스레드 환경에서는 동기화 기술을 사용하여 작업의 원 자성을 보장해야합니다.

public synchronized static ClassSingleton getInstance() { if (INSTANCE == null) { INSTANCE = new ClassSingleton(); } return INSTANCE; }

메서드 선언에서 동기화 된 키워드에 유의하십시오 . 메서드의 본문에는 여러 작업 (비교, 인스턴스화 및 반환)이 있습니다.

동기화가 없으면 두 스레드가 두 스레드 모두에 대해 INSTANCE == null 표현식 이 true 로 평가되어 결과적으로 ClassSingleton의 두 인스턴스 가 생성 되는 방식으로 실행을 인터리브 할 가능성이 있습니다 .

동기화 는 성능에 상당한 영향을 미칠 수 있습니다. 이 코드가 자주 호출되는 경우 지연 초기화 또는 이중 검사 잠금 과 같은 다양한 기술을 사용하여 속도를 높여야합니다 (컴파일러 최적화로 인해 예상대로 작동하지 않을 수 있음에 유의하십시오). “Singleton을 사용한 Double-Checked Locking“튜토리얼에서 자세한 내용을 볼 수 있습니다.

여러 인스턴스

JVM 자체와 관련된 싱글 톤과 관련된 몇 가지 다른 문제가있어 싱글 톤의 여러 인스턴스로 끝날 수 있습니다. 이러한 문제는 매우 미묘하며 각각에 대한 간략한 설명을 제공합니다.

  1. 싱글 톤은 JVM마다 고유해야합니다. 이는 내부가 분산 기술을 기반으로하는 분산 시스템 또는 시스템의 문제 일 수 있습니다.
  2. 모든 클래스 로더는 해당 버전의 싱글 톤을로드 할 수 있습니다.
  3. 아무도 그것에 대한 참조를 보유하지 않으면 싱글 톤이 가비지 수집 될 수 있습니다. 이 문제로 인해 한 번에 여러 개의 싱글 톤 인스턴스가있는 것은 아니지만 다시 만들 때 인스턴스가 이전 버전과 다를 수 있습니다.

6. 결론

이 빠른 자습서에서는 핵심 Java만을 사용하여 Singleton 패턴을 구현하는 방법과 일관성을 유지하는 방법과 이러한 구현을 사용하는 방법에 중점을 두었습니다.

이러한 예제의 전체 구현은 GitHub에서 찾을 수 있습니다.