JavaRush /Java Blog /Random-KO /디자인 패턴: 싱글톤

디자인 패턴: 싱글톤

Random-KO 그룹에 게시되었습니다
안녕하세요! 오늘 우리는 다양한 디자인 패턴에 대해 자세히 살펴보고 "싱글턴"이라고도 불리는 싱글턴 패턴부터 시작하겠습니다. 디자인 패턴: 싱글톤 - 1기억합시다: 일반적으로 디자인 패턴에 대해 우리는 무엇을 알고 있습니까? 디자인 패턴은 알려진 여러 문제를 해결하기 위해 따를 수 있는 모범 사례입니다. 디자인 패턴은 일반적으로 프로그래밍 언어와 관련이 없습니다. 이를 일련의 권장 사항으로 삼으면 실수를 방지하고 바퀴를 재발명하지 않을 수 있습니다.

싱글톤이란 무엇입니까?

싱글톤은 클래스에 적용할 수 있는 가장 간단한 디자인 패턴 중 하나입니다. 사람들은 때때로 "이 클래스는 싱글톤입니다"라고 말합니다. 이는 이 클래스가 싱글톤 디자인 패턴을 구현한다는 의미입니다. 때로는 하나의 객체만 생성할 수 있는 클래스를 작성해야 하는 경우도 있습니다. 예를 들어, 데이터베이스 로깅 또는 연결을 담당하는 클래스입니다. 싱글톤 디자인 패턴은 이러한 작업을 수행하는 방법을 설명합니다. 싱글톤은 다음 두 가지 작업을 수행하는 디자인 패턴입니다.
  1. 클래스가 클래스의 인스턴스를 하나만 갖도록 보장합니다.

  2. 이 클래스의 인스턴스에 대한 전역 액세스 지점을 제공합니다.

따라서 싱글톤 패턴의 거의 모든 구현에는 두 가지 특징이 있습니다.
  1. 개인 생성자. 클래스 자체 외부에서 클래스 객체를 생성하는 기능을 제한합니다.

  2. 클래스의 인스턴스를 반환하는 공용 정적 메서드입니다. 이 방법을 이라고 합니다 getInstance. 이는 클래스 인스턴스에 대한 전역 액세스 지점입니다.

구현 옵션

싱글톤 디자인 패턴은 다양한 방식으로 사용됩니다. 각 옵션은 나름대로 좋고 나쁩니다. 항상 그렇듯이 여기에는 이상이 없지만 이를 위해 노력해야 합니다. 하지만 먼저 무엇이 좋고 무엇이 나쁜지 정의하고, 어떤 측정 기준이 디자인 패턴 구현 평가에 영향을 미치는지 살펴보겠습니다. 긍정적인 것부터 시작해보자. 구현에 흥미와 매력을 부여하는 기준은 다음과 같습니다.
  • 지연 초기화: 애플리케이션이 필요할 때 정확하게 실행되는 동안 클래스가 로드되는 경우입니다.

  • 코드의 단순성과 투명성: 물론 지표는 주관적이지만 중요합니다.

  • 스레드 안전성: 다중 스레드 환경에서 올바르게 작동합니다.

  • 다중 스레드 환경의 고성능: 리소스를 공유할 때 스레드가 서로를 최소한으로 차단하거나 전혀 차단하지 않습니다.

이제 단점. 우리는 나쁜 관점에서 구현을 보여주는 기준을 나열합니다:
  • 지연되지 않은 초기화: 필요 여부에 관계없이 애플리케이션이 시작될 때 클래스가 로드되는 경우(역설적이지만 IT 세계에서는 게으른 것이 더 좋습니다)

  • 코드가 복잡하고 가독성이 좋지 않습니다. 측정항목도 주관적입니다. 피가 눈에서 나온다면 구현은 그저 그렇습니다.

  • 스레드 안전성이 부족합니다. 즉, "스레드 위험"입니다. 다중 스레드 환경에서 잘못된 작동이 발생합니다.

  • 다중 스레드 환경의 성능 저하: 스레드는 항상 서로를 차단하거나 리소스를 공유할 때 자주 차단합니다.

암호

이제 다양한 구현 옵션을 고려하여 장단점을 나열할 준비가 되었습니다.

간단한 솔루션

public class Singleton {
    private static final Singleton INSTANCE = new Singleton();

    private Singleton() {
    }

    public static Singleton getInstance() {
        return INSTANCE;
    }
}
가장 간단한 구현. 장점:
  • 코드의 단순성과 투명성

  • 스레드 안전성

  • 멀티스레드 환경에서 뛰어난 성능

단점:
  • 게으른 초기화가 아닙니다.
마지막 결함을 수정하기 위한 시도로 두 번째 구현을 얻었습니다.

지연 초기화

public class Singleton {
  private static Singleton INSTANCE;

  private Singleton() {}

  public static Singleton getInstance() {
    if (INSTANCE == null) {
      INSTANCE = new Singleton();
    }
    return INSTANCE;
  }
}
장점:
  • 지연된 초기화.

단점:
  • 스레드로부터 안전하지 않음

구현이 흥미롭습니다. 느리게 초기화할 수 있지만 스레드 안전성이 상실되었습니다. 문제 없습니다. 세 번째 구현에서는 모든 것을 동기화합니다.

동기화된 접근자

public class Singleton {
  private static Singleton INSTANCE;

  private Singleton() {
  }

  public static synchronized Singleton getInstance() {
    if (INSTANCE == null) {
      INSTANCE = new Singleton();
    }
    return INSTANCE;
  }
}
장점:
  • 지연된 초기화.

  • 스레드 안전성

단점:
  • 멀티스레드 환경에서 성능 저하

엄청난! 세 번째 구현에서는 스레드 안전성을 다시 가져왔습니다! 사실 느리네요... 이제 메서드가 getInstance동기화되어 한 번에 하나씩만 입력할 수 있습니다. 실제로 전체 메소드를 동기화할 필요는 없고 새 클래스 객체를 초기화하는 부분만 동기화하면 됩니다. synchronized그러나 새 객체를 생성하는 부분을 블록으로 간단히 감쌀 수는 없습니다 . 이는 스레드 안전성을 제공하지 않습니다. 조금 더 복잡합니다. 올바른 동기화 방법은 다음과 같습니다.

이중 확인 잠금

public class Singleton {
    private static Singleton INSTANCE;

  private Singleton() {
  }

    public static Singleton getInstance() {
        if (INSTANCE == null) {
            synchronized (Singleton.class) {
                if (INSTANCE == null) {
                    INSTANCE = new Singleton();
                }
            }
        }
        return INSTANCE;
    }
}
장점:
  • 지연된 초기화.

  • 스레드 안전성

  • 멀티스레드 환경에서 뛰어난 성능

단점:
  • 1.5 미만의 Java 버전에서는 지원되지 않습니다(휘발성 키워드는 버전 1.5에서 수정되었습니다).

이 구현 옵션이 올바르게 작동하려면 두 가지 조건 중 하나가 필요합니다. 변수는 , 또는 INSTANCE이어야 합니다 . 오늘 논의할 마지막 구현은 입니다 . finalvolatileClass Holder Singleton

클래스 보유자 싱글톤

public class Singleton {

   private Singleton() {
   }

   private static class SingletonHolder {
       public static final Singleton HOLDER_INSTANCE = new Singleton();
   }

   public static Singleton getInstance() {
       return SingletonHolder.HOLDER_INSTANCE;
   }
}
장점:
  • 지연된 초기화.

  • 스레드 안전성.

  • 멀티스레드 환경에서 높은 성능을 발휘합니다.

단점:
  • Singleton올바른 작동을 위해서는 클래스 객체가 오류 없이 초기화되도록 보장해야 합니다 . 그렇지 않으면 첫 번째 메서드 호출이 getInstance오류로 종료되고 ExceptionInInitializerError이후의 모든 호출은 실패하게 됩니다 NoClassDefFoundError.

구현이 거의 완벽합니다. 게으르고 스레드로부터 안전하며 빠릅니다. 그러나 마이너스에는 뉘앙스가 설명되어 있습니다. 싱글톤 패턴의 다양한 구현 비교표:
구현 지연 초기화 스레드 안전성 멀티스레딩 속도 언제 사용하나요?
간단한 솔루션 - + 빠른 절대. 또는 지연 초기화가 중요하지 않은 경우. 하지만 결코 나아지지는 않습니다.
지연 초기화 + - 해당 없음 멀티스레딩이 필요하지 않을 때 항상
동기화된 접근자 + + 느리게 절대. 또는 멀티스레딩 작업 속도가 중요하지 않은 경우. 하지만 결코 나아질 수는 없어
이중 확인 잠금 + + 빠른 싱글톤을 생성할 때 예외를 처리해야 하는 드문 경우입니다. (Classholder Singleton이 적용되지 않는 경우)
클래스 보유자 싱글톤 + + 빠른 멀티스레딩이 필요할 때마다 항상 문제 없이 싱글톤 클래스 객체가 생성된다는 보장이 있습니다.

싱글턴 패턴의 장점과 단점

일반적으로 싱글톤은 예상되는 작업을 정확하게 수행합니다.
  1. 클래스가 클래스의 인스턴스를 하나만 갖도록 보장합니다.

  2. 이 클래스의 인스턴스에 대한 전역 액세스 지점을 제공합니다.

그러나 이 패턴에는 단점이 있습니다.
  1. 싱글톤은 SRP(단일 책임 원칙)를 위반합니다. 싱글톤 클래스는 즉각적인 책임 외에도 복사본 수를 제어합니다.

  2. 싱글톤에 대한 일반 클래스나 메서드의 종속성은 클래스의 공개 계약에 표시되지 않습니다.

  3. 전역 변수가 잘못되었습니다. 싱글톤은 결국 하나의 거대한 전역 변수로 변합니다.

  4. 싱글톤이 있으면 일반적으로 애플리케이션의 테스트 용이성과 특히 싱글톤을 사용하는 클래스가 줄어듭니다.

이제 다 끝났습니다. 우리는 싱글턴 디자인 패턴을 살펴보았습니다. 이제 프로그래머 친구들과의 평생 대화에서 당신은 그것에 대해 좋은 점뿐만 아니라 나쁜 점에 대해서도 몇 마디 말할 수 있을 것입니다. 새로운 지식을 습득하는 데 행운을 빕니다.

추가 자료:

코멘트
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION