자바 단일 예 모드 의 가장 전형 적 인 예

개념:
자바 에서 단일 모델 은 흔히 볼 수 있 는 디자인 모델 로 단일 모델 은 세 가지 로 나 뉜 다. 게으름뱅이 식 단일 사례, 굶 주 린 식 단일 사례, 등록 식 단일 사례 세 가지 로 나 뉜 다.단일 모드 의 특징 은 다음 과 같다. 1. 단일 클래스 는 하나의 실례 만 있 을 수 있다.2. 단일 사례 류 는 자신 이 자신의 유일한 인 스 턴 스 를 만들어 야 합 니 다.3. 단일 클래스 는 모든 다른 대상 에 게 이 인 스 턴 스 를 제공 해 야 합 니 다.단일 모드 는 하나의 인 스 턴 스 만 있 고 자체 적 으로 예화 되 어 전체 시스템 에 이 인 스 턴 스 를 제공 하도록 확보 합 니 다.컴퓨터 시스템 에 서 는 스 레 드 탱크, 캐 시, 로그 대상, 대화 상자, 프린터, 그래 픽 카드 의 드라이버 대상 이 하나의 예 로 설계 되 어 있 습 니 다.이러한 응용 은 모두 많 든 적 든 자원 관리자 의 기능 을 가지 고 있다.컴퓨터 마다 프린터 가 몇 개 있 을 수 있 지만 프린터 스 풀 러 는 두 개의 인쇄 작업 이 동시에 프린터 에 출력 되 는 것 을 피 할 수 있 습 니 다.모든 컴퓨터 에는 몇 개의 통신 포트 가 있 을 수 있 으 며, 시스템 은 하나의 통신 포트 가 두 개의 요청 에 동시에 호출 되 지 않도록 집중 적 으로 관리 해 야 한다.한 마디 로 단일 모델 을 선택 한 것 은 불일치 상 태 를 피하 고 정 치 를 많이 하지 않도록 하기 위 한 것 이다.
   단일 모드 는 많은 장점 이 있 습 니 다. 인 스 턴 스 대상 의 중복 생 성 을 피 할 수 있 고 매번 대상 을 만 드 는 시간 비용 을 줄 일 수 있 을 뿐만 아니 라 메모리 공간 도 절약 할 수 있 습 니 다.여러 개의 인 스 턴 스 를 조작 해서 발생 하 는 논리 적 오 류 를 피 할 수 있 습 니 다.만약 에 한 대상 이 전체 응용 프로그램 을 관통 시 키 고 전체적인 통일 관리 통제 역할 을 할 수 있다 면 단일 모델 은 고려 해 야 할 선택 일 수 있다.
       단일 모드 에는 여러 가지 문법 이 있 는데 대부분 문법 이 다소 부족 하 다.다음은 이 몇 가지 서법 에 대해 각각 소개 할 것 이다.
1. 굶 주 린 남자 모델
public class Singleton{
    private static final Singleton instance = new Singleton();
    private Singleton(){}
    public static Singleton newInstance(){
        return instance;
    }
}

       코드 에서 볼 수 있 듯 이 클래스 의 구조 함 수 는 private 로 정의 되 어 다른 클래스 가 이러한 것 을 예화 할 수 없 도록 한 다음 에 정적 인 인 스 턴 스 를 제공 하고 호출 자 에 게 되 돌려 줍 니 다.굶 주 린 모드 는 가장 간단 한 실현 방식 이다. 굶 주 린 모드 는 클래스 를 불 러 올 때 실례 를 만 들 고 실례 는 전체 프로그램 주기 에 존재 한다.클래스 로 딩 할 때 만 인 스 턴 스 를 만 드 는 것 이 좋 습 니 다. 여러 스 레 드 가 여러 개의 인 스 턴 스 를 만 드 는 상황 이 존재 하지 않 고 다 중 스 레 드 동기 화 문 제 를 피 할 수 있 습 니 다.단점 도 뚜렷 하 다. 이 사례 가 사용 되 지 않 아 도 생 성 되 고 클래스 가 불 러 온 후에 생 성 되 어 메모리 가 낭비 된다.
 
       이러한 실현 방식 은 단일 메모리 사용량 이 비교적 적 고 초기 화 할 때 사용 되 는 상황 에 적합 하 다.그러나 만약 에 한 번 에 차지 하 는 메모리 가 비교적 크 거나 한 번 에 특정한 장면 에서 만 사용 할 수 있다 면 굶 주 린 사람 모드 를 사용 하 는 것 은 적당 하지 않다. 이 럴 때 게으름뱅이 모드 로 로드 를 지연 시 켜 야 한다.
2. 게으름뱅이 모드
public class Singleton{
    private static Singleton instance = null;
    private Singleton(){}
    public static Singleton newInstance(){
        if(null == instance){
            instance = new Singleton();
        }
        return instance;
    }
}

       게으름뱅이 모드 에서 단일 예 는 필요 할 때 만 듭 니 다. 단일 예 가 만 들 어 졌 다 면 인 터 페 이 스 를 다시 호출 하면 새로운 대상 을 만 들 지 않 고 이전에 만 든 대상 으로 돌아 갑 니 다.만약 에 하나의 사례 를 사용 하 는 횟수 가 적 고 하나의 사례 를 만 드 는 데 소모 되 는 자원 이 비교적 많다 면 하나의 사례 를 필요 에 따라 만들어 야 한다. 이 럴 때 게으름뱅이 모델 을 사용 하 는 것 이 좋 은 선택 이다.그러나 이곳 의 게으름뱅이 모드 는 스 레 드 안전 문 제 를 고려 하지 않 았 습 니 다. 여러 스 레 드 에서 getInstance () 방법 을 동시에 호출 하여 여러 개의 인 스 턴 스 를 만 들 수 있 기 때문에 스 레 드 동기 화 문 제 를 잠 그 고 해결 해 야 합 니 다. 다음 과 같 습 니 다.
public class Singleton{
    private static Singleton instance = null;
    private Singleton(){}
    public static synchronized Singleton newInstance(){
        if(null == instance){
            instance = new Singleton();
        }
        return instance;
    }
}

 
3. 이중 검사 자물쇠
       자 물 쇠 를 채 우 는 게으름뱅이 모델 은 스 레 드 병행 문 제 를 해결 하고 로드 지연 을 실현 하 는 것 처럼 보이 지만 성능 문제 가 존재 하고 완벽 하지 않다.synchronized 수식 의 동기 화 방법 은 일반 방법 보다 훨씬 느 리 며, getInstance () 를 여러 번 호출 하면 누적 되 는 성능 손실 이 비교적 크다.그래서 이중 검증 자물쇠 가 생 겼 으 니, 먼저 실현 코드 를 살 펴 보 자.
public class Singleton {
    private static Singleton instance = null;
    private Singleton(){}
    public static Singleton getInstance() {
        if (instance == null) {
            synchronized (Singleton.class) {
                if (instance == null) {//2
                    instance = new Singleton();
                }
            }
        }
        return instance;
    }
}

       위 에 동기 코드 블록 밖 에 인 스 턴 스 가 비어 있다 는 판단 을 볼 수 있 습 니 다.단일 대상 은 한 번 만 만 들 수 있 기 때문에 나중에 getInstance () 를 다시 호출 하면 단일 대상 으로 돌아 가 야 합 니 다.따라서 대부분의 경우 getInstance () 를 호출 하면 동기 코드 블록 에 실행 되 지 않 아 프로그램 성능 을 향상 시킨다.그러나 한 가지 상황 을 고려 해 야 한다. 만약 에 두 개의 스 레 드 A, B, A 가 if (instance = = null) 문 구 를 실 행 했 을 때 한 개의 대상 이 만 들 지 않 았 다 고 생각 할 것 이다. 이때 스 레 드 는 B 까지 똑 같은 문 구 를 실 행 했 고 B 도 한 개의 대상 이 만 들 지 않 았 다 고 생각 한 다음 에 두 개의 스 레 드 는 동기 코드 블록 을 순서대로 실행 하고 각각 하나의 단일 대상 을 만 들 었 다.이 문 제 를 해결 하기 위해 서 는 동기 코드 블록 에 if (instance = = null) 문 구 를 추가 해 야 합 니 다. 즉, 위 에서 본 코드 2 입 니 다.
 
       우 리 는 이중 검사 자 물 쇠 를 보면 로드 지연 을 실현 하고 스 레 드 병행 문 제 를 해결 하 는 동시에 집행 효율 문제 도 해결 하 는 것 을 보 았 습 니 다. 정말 실수 가 없 습 니까?
       자바 의 명령 정렬 최적화 에 대해 언급 합 니 다.명령 재배 치 최적화 란 원래 의 의 미 를 바 꾸 지 않 고 명령 의 실행 순 서 를 조정 하여 프로그램 을 더욱 빨리 실행 하 게 하 는 것 을 말한다.JVM 에는 컴 파일 러 최적화 와 관련 된 내용 이 규정 되 어 있 지 않다. 즉, JVM 은 자 유 롭 게 명령 재 정렬 의 최 적 화 를 할 수 있다.
       이 문제 의 관건 은 명령 정렬 최적화 의 존재 로 인해 Singleton 을 초기 화하 고 대상 주 소 를 intance 필드 에 부여 하 는 순서 가 불확실 하 다 는 것 이다.한 스 레 드 가 단일 대상 을 만 들 때 구조 방법 이 호출 되 기 전에 이 대상 에 게 메모리 공간 을 할당 하고 대상 의 필드 를 기본 값 으로 설정 합 니 다.이 때 분 배 된 메모리 주 소 를 인 스 턴 스 필드 에 할당 할 수 있 지만 대상 이 초기 화 되 지 않 았 을 수도 있 습 니 다.다른 스 레 드 에 이 어 getInstance 를 호출 하면 상태 가 정확 하지 않 은 대상 을 가 져 오 면 프로그램 이 잘못 됩 니 다.
       이상 은 이중 검증 자물쇠 가 효력 을 잃 는 원인 이지 만 다행히 JDK 1.5 및 그 후 버 전에 volatile 키 워드 를 추 가 했 습 니 다.volatile 의 한 의 미 는 명령 의 정렬 최 적 화 를 금지 하 는 것 이다. 또한 intance 변수 가 할당 되 었 을 때 대상 이 초기 화 되 어 위 에서 말 한 문 제 를 피 할 수 있다.코드 는 다음 과 같 습 니 다:
public class Singleton {
    private static volatile Singleton instance = null;
    private Singleton(){}
    public static Singleton getInstance() {
        if (instance == null) {
            synchronized (Singleton.class) {
                if (instance == null) {
                    instance = new Singleton();
                }
            }
        }
        return instance;
    }
}

 
4. 정적 내부 클래스
       위의 세 가지 방식 을 제외 하고 또 다른 한 가지 사례 를 실현 하 는 방식 도 있 고 정적 내부 류 를 통 해 이 루어 진다.우선 실현 코드 를 살 펴 보 자.
public class Singleton{
    private static class SingletonHolder{
        public static Singleton instance = new Singleton();
    }
    private Singleton(){}
    public static Singleton newInstance(){
        return SingletonHolder.instance;
    }
}

 
       이 방식 역시 하나의 인 스 턴 스 인 스 턴 스 만 만 들 수 있 도록 클래스 로 딩 체 제 를 이용 했다.이 는 굶 주 린 사람 모델 과 마찬가지 로 로드 체 제 를 이용 하기 때문에 다 중 스 레 드 병발 문제 가 존재 하지 않 는 다.다른 것 은 내부 클래스 에서 대상 인 스 턴 스 를 만 드 는 것 입 니 다.이렇게 되면 응용 프로그램 에서 내부 클래스 를 사용 하지 않 으 면 JVM 은 이 단일 클래스 를 불 러 오지 않 고 단일 대상 을 만 들 지 않 아 게으름뱅이 식 지연 로드 를 실현 합 니 다.이런 방식 은 로드 지연 과 스 레 드 안전 을 동시에 보장 할 수 있다 는 것 이다.
5. 매 거
       다시 본 고가 소개 하고 자 하 는 마지막 실현 방식 인 매 거 를 살 펴 보 자.
public enum Singleton{
    instance;
    public void whateverMethod(){}    
}

 
위 에서 언급 한 네 가지 사례 를 실현 하 는 방식 은 모두 공 통 된 단점 이 있다.
1) 직렬 화 를 위해 서 는 별도의 작업 이 필요 하 다. 그렇지 않 으 면 직렬 화 된 대상 을 반 직렬 화 할 때마다 새로운 인 스 턴 스 를 만들어 야 한다.
2) 반사 로 개인 구조 기 를 강제로 호출 할 수 있 습 니 다 (이 를 피 하려 면 구조 기 를 수정 하여 두 번 째 인 스 턴 스 를 만 들 때 이상 을 던 질 수 있 습 니 다).
       한편, 매 거 진 류 는 이 두 가지 문 제 를 잘 해결 했다. 매 거 진 을 사용 하면 스 레 드 안전 과 반사 호출 방지 구조 기 를 제외 하고 자동 직렬 화 체 제 를 제공 하여 반 직렬 화 를 방지 할 때 새로운 대상 을 만 들 수 있다.그래서 '이 펙 티 브 자바' 저자 가 추천 하 는 방법 이다.그러나 실제 업무 에서 이렇게 쓰 는 사람 은 드물다.
 
 
총결산
       본 고 는 다섯 가지 자바 에서 단일 사례 를 실현 하 는 방법 을 정리 했다. 그 중에서 앞의 두 가지 가 모두 완벽 하지 않 고 이중 검증 자물쇠 와 정태 내부 류 의 방식 으로 대부분의 문 제 를 해결 할 수 있 으 며 평소에 업무 에서 가장 많이 사용 하 는 것 도 이 두 가지 방식 이다.매 거 방식 은 여러 가지 문 제 를 완벽 하 게 해 결 했 지만 다소 생소 하 다.개인의 건 의 는 특별한 수요 가 없 는 상황 에서 세 번 째 와 네 번 째 방식 으로 단일 모델 을 실현 하 는 것 이다.
참고:https://blog.csdn.net/goodlixueyong/article/details/51935526 
 
 

좋은 웹페이지 즐겨찾기