자바 디자인 모델 의 단일 예 모드 상세 설명

8208 단어 자바단일 모드
단일 모델 은 매우 흔히 볼 수 있 는 디자인 모델 로 그 의미 도 매우 간단 하 며 하나의 유형 은 외부 에 유일한 인 스 턴 스 를 제공한다.아래 의 모든 코드 는 github 에 있다.
소스 코드 전체 프로젝트 는 디자인 모델 뿐만 아니 라 다른 자바 SE 지식 도 있 습 니 다.스타,포크 를 환영 합 니 다.
단일 모드 UML 그림

단일 모드 의 관건
위의 UML 그림 을 통 해 우 리 는 단일 모델 의 특징 이 다음 과 같다 는 것 을 알 수 있다.
1.구조 기 는 개인 적 인 것 으로 외부 클래스 호출 구조 기 를 허용 하지 않 습 니 다.
2.외부 접근 을 위 한 방법 을 제공 합 니 다.이 방법 은 단일 사례 의 인 스 턴 스 를 되 돌려 줍 니 다.
어떻게 단일 모델 을 실현 합 니까?
위 에서 이미 단일 모델 의 관건 을 제 시 했 기 때문에 우리 의 실현 은 위의 두 가지 만 만족 시 키 면 된다.그러나 단일 모델 의 실현 방식 이 비교적 느슨 하기 때문에 서로 다른 실현 방식 에 서로 다른 문제 가 있 을 수 있다.우 리 는 단일 모델 의 실현 에 대해 분 류 를 해서 어떤 다른 실현 방식 이 있 는 지 볼 수 있다.
1.단일 대상 의 생 성 시기 에 따라 굶 주 린 사람 모델 과 게으름뱅이 모델 로 나 눌 수 있다.굶 주 린 사람 은 클래스 를 불 러 올 때 대상 을 만 드 는 것 을 말한다.그러나 대상 을 만 드 는 데 자원 이 소모 되 어 클래스 로드 가 느 릴 수 있 지만 대상 을 얻 는 속도 가 빠르다 는 것 이 장점 입 니 다.이미 만 들 어 졌 기 때 문 입 니 다.게 으 른 사람 은 굶 주 린 사람 에 비해 하나의 대상 으로 돌아 가 야 할 때 대상 을 만 들 고 클래스 를 불 러 올 때 초기 화 되 지 않 으 며 좋 은 점 과 단점 도 말 하지 않 는 다.
2.스 레 드 안전 실현 여부 에 따라 일반 게으름뱅이 모델 과 같은 스 레 드 안전 하지 않 은 쓰기,굶 주 린 남자 모델,잠 금 된 게으름뱅이 모델 을 이중 으로 검사 하고 정적 내부 류 나 매 거 진 류 등 을 통 해 이 루어 진 스 레 드 안전 한 쓰기 로 나 눌 수 있다.
스 레 드 가 안전 하지 않 은 단일 모드

public class SimpleSingleton {

  private static SimpleSingleton simpleSingleton;

  private SimpleSingleton(){

  }

  public static SimpleSingleton getInstance(){
    if (simpleSingleton == null) {
      simpleSingleton = new SimpleSingleton();
    }
    return simpleSingleton;
  }
}

우선 게으름뱅이 모델 의 실현 임 을 알 수 있다.getInstance 에 있 을 때 만 하나의 대상 을 만 들 수 있 기 때문이다.그런데 왜 그 는 스 레 드 가 안전 하지 않 은 것 일 까?2 개의 스 레 드 가 동시에 if(simpleSingleton==null)에 들 어 갈 수 있다 는 판단 이 동시에 simpleSingleton 대상 을 만 들 었 기 때문이다.
DCL 게으름뱅이 모드
위의 방법 은 스 레 드 가 안전 하지 않 은 문제 가 존재 한 다 는 것 을 알 수 있 습 니 다.우 리 는 동기 화 키워드 synchronized 로 스 레 드 안전 을 실현 할 수 있 습 니 다.우 리 는 먼저 점차적으로 분석 하고 먼저 synchronized 로 위의 게으름뱅이 모델 을 고 칩 니 다.코드 는 다음 과 같 습 니 다.

public class DCLSingleton {

  private static DCLSingleton singleton;
  private DCLSingleton(){
  }

  public synchronized static DClSingleton getSingleton(){
    if (singleton == null) {
      singleton = new DCLSingleton();
    }
    return singleton;
  }

}

이렇게 하면 두 개의 스 레 드 가 동시에 이 방법 을 실행 하지 않 을 것 이 라 고 효과적으로 보장 할 수 있 지만 이 효율 도 너무 낮 습 니 다.인 스 턴 스 를 만 든 후에 인 스 턴 스 대상 을 얻 을 때마다 동기 화 를 해 야 하기 때문에 synchronized 의 동기 화 보증 대가 가 비교적 크기 때문에 이 를 바탕 으로 개조 할 수 있 습 니 다.이미 만들어 진 후에 동기 화 할 필요 가 없습니다.우 리 는 다음 과 같은 형식 으로 바 꿀 수 있 습 니 다.

  public static DCLSingleton getSingleton(){
    if (singleton == null) {
      synchronized (DCLSingleton.class) {
        if (singleton == null) {
          singleton = new DCLSingleton();
        }
      }
    }
    return singleton;
  }
다른 코드 는 변 하지 않 고 이 방법 만 봅 니 다.이 방법의 이중 if(singleton==null)는 스 레 드 안전 을 효과적으로 보장 할 수 있 습 니 다.예 를 들 어 두 스 레 드 가 이 방법 에 동시에 들 어 갈 때 첫 번 째 if 는 둘 다 들 어 갑 니 다.아래 의 코드 이지 만 동기 코드 블록 에 부 딪 히 면 한 개 만 먼저 들 어가 고 들 어 갈 때 계속 판단 하고 다시 빈 것 으로 판단 해 야 진정 으로 대상 을 만 들 수 있 습 니 다.만약 에 진행 하지 않 으 면 두 번 째 판단 은 첫 번 째 로 들 어 온 스 레 드 에 있어 대상 을 만 들 었 지만 두 번 째 스 레 드 는 그 다음 에 대상 을 만 드 는 작업 을 수행 할 것 입 니 다.첫 번 째 스 레 드 가 성공 적 으로 만 들 어 졌 는 지 모 르 기 때 문 입 니 다.따라서 두 차례 의 판정 이 필요 하 다.
그런데 정말 이렇게 간단하게 라인 안전 을 보장 한 건 가요?우 리 는 이 과정 을 자세히 분석 해 보 자.singleton=new DCLSingleton();이 코드 는 실제로 세 개의 조작 이다.
1.DCLSingleton 인 스 턴 스 에 메모리 할당
2.DCLSingleton()의 구조 함 수 를 호출 하여 구성원 필드 초기 화
3.singleton 대상 을 분 배 된 메모리 공간 으로 가리킨다.
JDK 1.5 이전 에는 위의 3 개의 실행 순서 가 일정 하지 않 아 1-2-3 또는 1-3-2 일 수 있 었 다.1-3-2 라면 첫 번 째 스 레 드 가 세 번 째 단 계 를 실행 한 후에 두 번 째 스 레 드 가 즉시 실행 되 지만 아직 초기 화 되 지 않 아 사용 할 때 오류 가 발생 합 니 다.JDK 1.5 이후 에 우 리 는 volatile 키워드 로 이 1-2-3 의 순 서 를 보장 할 수 있다.따라서 getSingleton()방법 을 위의 모양 으로 바 꾸 는 것 외 에 private static DCLSingleton singleton 도 필요 합 니 다.private static volatile DCLSingleton singleton 으로 바 꾸 기;이렇게 하면 스 레 드 동기 화 게으름뱅이 쓰기 의 단일 예 모델 을 진정 으로 보장 한다.
굶 주 린 자의 서법
굶 주 린 사람 이 쓰 는 방법 은 많은 변형 이 있 지만 어떤 변형 이 든 스 레 드 의 안전 을 보장 할 수 있 습 니 다.굶 주 린 사람 이 쓰 는 방법 은 클래스 로 딩 할 때 대상 의 초기 화 를 완 성 했 기 때 문 입 니 다.클래스 로 딩 은 그들 이 타고 난 스 레 드 안전 을 보장 합 니 다.흔히 볼 수 있 는 2 중 굶 주 린 남자 의 글 씨 를 보 여 드 리 겠 습 니 다.

public class HungrySingleton {
  private static final HungrySingleton singleton = new HungrySingleton();

  private HungrySingleton(){

  }

  public static HungrySingleton getSingleton(){
    return singleton;
  }
}
public class HungrySingleton {
  private static final HungrySingleton singleton = new HungrySingleton();

  private HungrySingleton(){

  }

//  public static HungrySingleton getSingleton(){
//    return singleton;
//  }
}

이 두 가지 초기 화 사례 의 대상 위 는 모두 일치 하 며 final 을 통 해 대상 을 확보 하 는 유일한 것 이다.다른 것 은 단일 대상 을 호출 하 는 방식 이다.첫 번 째 는 getSingleton()을 통 해,두 번 째 는 클래스.클래스 변 수 를 통 해.
정적 내부 클래스 구현 단일 모드
이중 검사 잠 금(DCL)은 단일 모드 를 실현 합 니 다.스 레 드 가 안전 하지 않 은 문 제 를 해결 하고 자원 의 게 으 름 로드 를 확보 하지만 필요 할 때 만 정례 화 된 작업 을 할 수 있 습 니 다.그러나 어떤 경우(예 를 들 어 JDK 가 1.5 보다 낮 음)DCL 이 효력 을 잃 기 때문에 간결 하고 게 으 른 로드 방법 으로 단일 모델 을 실현 하 는 방법 이 있다.쓰 는 방법 은 다음 과 같다.

public class StaticSingleton {

  private StaticSingleton(){
  }
  public static final StaticSingleton getInstance(){
    return Holder.singleton;
  }

  private static class Holder{
    private static final StaticSingleton singleton = new StaticSingleton();
  }
}

정적 내부 클래스 의 형식 을 통 해 단일 클래스 의 초기 화 를 실현 합 니 다.그 특성 은 ClassLoader 를 통 해 단일 대상 을 확보 하 는 유일한 것 입 니 다.그러나 이것 은 게 으 른 로 딩 입 니 다.Holder 클래스 가 호출 될 때,즉 getInstance 가 호출 될 때 만 Holder 클래스 를 불 러 와 서 대상 을 만 들 수 있 기 때 문 입 니 다.
매 거 클래스 구현 단일 모드
코드 직접 보기:

public enum EnumSingleton {
  SINGLETON;
  public void doSometings(){
    
  }
}
사용 할 때 는 EnumSingleton.SHINGLETON.doSomethings()를 통 해 직접 사용 합 니 다.매 거 류 의 타고 난 특성 은 두 개의 인 스 턴 스 가 없 을 것 을 보장 하고 첫 번 째 방문 할 때 만 실례 화 되 며 게 으 른 로 딩 상황 입 니 다.
정말 새로운 대상 을 다시 만 들 지 않 을까요?
일반적인 단일 클래스 의 getInstance()방법 을 호출 하 는 상황 에서 스 레 드 안전 한 쓰기 방법 을 사용 하면 새로운 대상 을 만 들 지 않 지만 자바 는 많은 특이 한 기술 과 사용 을 제공 합 니 다.아래 의 사용 은 일반적인 단일 사례 를 파괴 할 수 있 습 니 다.
  • 반 직렬 화
  • 반사
  • 클론
  • 분포 식 환경 에서 여러 종류의 캐리어
  • 단일 모드 를 실현 하 는 방법 을 제외 하고 나머지 모든 방법 은 상기 네 가지 상황 에 부 딪 히 면 대상 을 다시 만 듭 니 다.이 유 는 다음 과 같다.
  • 반 직렬 화 는 특수 한 readResolve()방법 으로 새로운 대상 을 만 듭 니 다.우 리 는 그 가 다시 만 드 는 것 이 아니 라 원래 의 인 스 턴 스 로 돌아 가도 록 이 방법 을 다시 쓸 수 있다.
  • 반 사 는 개인 적 인 구조 함 수 를 얻 을 수 있 습 니 다.구조 함수 에 하나의 판단 만 추가 할 수 있 습 니 다.대상 이 null 이 아니라면 운행 시 이상 을 던 집 니 다.그렇지 않 으 면 매 거 진 것 만 해결 할 수 있 습 니 다.매 거 진 자체 의 특성 때 문 입 니 다.
  • 복 제 는 메모리 공간의 내용 을 직접 복사 하기 때문에 자신 만 이 단일 클래스 의 clone 방법 을 다시 쓸 수 있 습 니 다.그렇지 않 으 면 매 거 진 것 만 해결 할 수 있 습 니 다.매 거 진 것 은 복제 방법 이 없 기 때 문 입 니 다.
  • 다 분포 식 환경 은 우리 가 상술 한 여러 가지 사례 의 작성 방법 은 모두 클래스 로 더 의 특성 에 의존 하지만 static 의 역할 은 클래스 로 더 만 책임 지기 때문에 프로젝트 에 여러 개의 클래스 로 더 가 존재 할 때 여러 개의 인 스 턴 스 를 만 들 수 있 습 니 다.이런 통 상 은 제3자 라 이브 러 리 로 해결 해 야 합 니 다.
  • 언제 단일 모드 를 사용 합 니까?어떤 형식의 단일 모드 를 사용 합 니까?
    단일 모드 는 두 가지 비교적 적합 한 사용 장면 이 있다.
    첫 번 째 는 특정한 대상 을 만 드 는 데 필요 한 대가 가 비교적 크다 는 것 이다.빈번 한 창설 과 소각 대상 으로 인해 발생 하 는 자원 에 대한 낭 비 를 피하 기 위해 단일 모델 을 사용 하 는 것 을 고려한다.
    두 번 째 는 이 대상 이 하나 밖 에 없어 야 한 다 는 것 이다.예측 할 수 없 는 오류 나 프로그램의 혼란 을 초래 할 수 있다.예 를 들 어 하나의 번호 생 성기,하나의 캐 시 등 이다.
    사용 하 는 단일 모드 에 대해 이해 해 야 할 로 딩 자원 은 굶 주 린 사람 으로 쓰 는 것 입 니 다.안 드 로 이 드 응용 프로그램 에서 많은 대상 이 시작 할 때 바로 사용 해 야 합 니 다.예 를 들 어 시작 할 때 카메라 설정 의 클래스 관리 미리 보기 그림 의 cache 류 등 입 니 다.즉각 적 으로 필요 하지 않 거나 일관 되 게 응용 되 지 않 으 면 굶 주 린 사람 이 쓰 는 방법 을 사용 할 필요 가 없고 게으름뱅이 가 쓰 는 방법(DCL 또는 정적 내부 류 실현)이라는 두 가 지 는 일반적인 상황 에서 문제 가 발생 하지 않 는 다 는 것 을 고려 할 수 있다.
    이상 이 바로 본 고의 모든 내용 입 니 다.여러분 의 학습 에 도움 이 되 고 저 희 를 많이 응원 해 주 셨 으 면 좋 겠 습 니 다.

    좋은 웹페이지 즐겨찾기