자바 에서 단일 모드 를 어떻게 정확하게 쓰 는 지 상세 하 게 설명 합 니 다.

6248 단어 Java단일 모드
단일 모델 은 디자인 모델 에서 가장 이해 하기 쉽 고 손 으로 코드 를 쓰기 쉬 운 모델 이 라 고 할 수 있 지만 그 중에서 관련 된 지식 이 하나 도 없어 서 면접 문제 로 자주 시험 을 본다.일반적인 사례 는 모두 다섯 가지 표기 법 이다.게으름뱅이,굶 주 린 사람,이중 검사 자물쇠,정적 내부 류 와 매 거 진 이다.학습 과정의 과정 을 기록 하기 위해 몇 가지 흔히 볼 수 있 는 단일 문법 을 정리 했다.

청동 5:(Lazy-loaded,하지만 라인 이 안전 하지 않 음)
하나의 사례 모델 을 실현 하 겠 다 는 질문 에 많은 사람들의 첫 반응 은 다음 과 같은 코드 를 쓰 는 것 이 었 다.교과서 에서 도 이렇게 가 르 쳤 다.

public class Singleton {
 private static Singleton instance;
 private Singleton(){}
 public static Singleton getInstance() {
 if (instance == null) {
 instance = new Singleton();
 }
 return instance;
 }
}
이 코드 는 간단명료 하고 지연 로드 모드 를 사 용 했 지만 라인 이 안전 하지 않 습 니 다.다 중 스 레 드 환경 에서 getInstance()방법 을 호출 하면 여러 스 레 드 가 if 구문 에 들 어 가 는 프로그램 코드 블록 이 발생 할 수 있 습 니 다.
게으름뱅이 식:synchronized(Lazy-loaded,라인 은 안전 하지만 효율 적 이지 않 음)
위의 문 제 를 해결 하기 위해 서 가장 쉬 운 방법 은 전체 getInstance()방법 을 동기 화(synchronized)로 설정 하 는 것 입 니 다.

public class Singleton {
 private static Singleton instance;
 private Singleton() {}
 public static synchronized Singleton getInstance() {
 if (instance == null) {
 instance = new Singleton();
 }
 return instance;
 }
}
스 레 드 안전,로드 지연 을 했 지만 효율 적 이지 않 습 니 다.getInstance()방법 은 언제든지 하나의 스 레 드 만 호출 할 수 있 기 때 문 입 니 다.그러나 synchronized 작업 은 첫 번 째 호출 때 만 필요 합 니 다.즉,첫 번 째 인 스 턴 스 대상 을 만 들 때 입 니 다.이 모드 는 단일 생 성 이 끝 난 후에 도 매번 하나의 스 레 드 만 getInstance()방법 에 접근 할 수 있 고 잠재 적 인 성능 문 제 를 초래 할 수 있 습 니 다.이중 검사 자 물 쇠 를 끌 어 냈 다.
굶 주 린 사람:static final field(Lazy-loaded 가 아 닌)
이 방법 은 매우 간단 합 니 다.하나의 인 스 턴 스 가 static final 로 설명 되 어 있 기 때문에 처음으로 메모리 에 클래스 를 불 러 올 때 초기 화 되 기 때문에 인 스 턴 스 대상 을 만 드 는 것 은 스 레 드 가 안전 합 니 다(JVM 에서 보증 합 니 다).

public class Singleton{
 //        
 private static final Singleton instance = new Singleton();
 private Singleton(){}
 public static Singleton getInstance(){  // Singleton with static factory
 return instance;
 }
}
이것 은 게 으 른 로 딩 모드 가 아 닙 니 다.인 스 턴 스 는 로 딩 클래스 를 불 러 온 후에 처음부터 초기 화 됩 니 다.클 라 이언 트 가 getInstance()방법 을 호출 하지 않 더 라 도.이 로 인해 일부 사용 제한 이 생 길 수 있 습 니 다.예 를 들 어 Singleton 인 스 턴 스 의 생 성 은 매개 변수 나 설정 파일 에 의존 하 는 것 입 니 다.getInstance()전에 특정한 방법 으로 파 라 메 터 를 설정 해 야 합 니 다.그러면 이러한 단일 쓰기 방법 은 사용 할 수 없습니다.비슷 한 방법 은 다음 과 같다.

public class Singleton{
 public static final Singleton instance = new Singleton(); // Singleton with public final field
 private Singleton(){}
}
// <Effective Java> 14         
이중 검사 자물쇠+volatile(Lazyload,스 레 드 는 안전 하지만 난해 함)
이중 검사 잠 금 모드(double checked locking pattern)는 동기 블록 에 잠 금 을 추가 하 는 방법 입 니 다.프로그래머 는 인 스 턴 스=null 을 두 번 검사 하기 때문에 이중 검사 자물쇠 라 고 부 릅 니 다.한 번 은 동기 블록 밖 에 있 고 한 번 은 동기 블록 안에 있 습 니 다.왜 동기 블록 안에서 다시 한 번 검사 해 야 합 니까?동기 블록 밖의 if 에 여러 개의 스 레 드 가 함께 들 어 갈 수 있 기 때문에 동기 블록 에서 2 차 검 사 를 하지 않 으 면 여러 개의 인 스 턴 스 대상 이 생 성 됩 니 다.

public static Singleton getSingleton() {
 if (instance == null) {       //Single Checked
  synchronized (Singleton.class) {
   if (instance == null) {     //Double Checked
    instance = new Singleton();
   }
  }
 }
 return instance ;
}
이 코드 는 보기에 매우 완벽 해 보이 지만,애석 하 게 도 그것 은 문제 가 있다.주로 인 스 턴 스=new Singleton()이라는 말 이 있 습 니 다.이것 은 원자 조작 이 아 닙 니 다.사실은 JVM 에서 이 말 은 다음 과 같은 세 가지 일 을 했 습 니 다.
인 스 턴 스에 메모리 할당
  • Singleton 의 구조 함 수 를 호출 하여 구성원 변 수 를 초기 화 합 니 다
  • 인 스 턴 스 대상 을 분 배 된 메모리 공간 으로 가리 키 기(이 단 계 를 실행 하면 인 스 턴 스 는 null 이 아 닙 니 다)그러나 JVM 의 JIT 컴 파일 러 에는 명령 재 정렬 최적화 가 존재 한다.즉 위의 두 번 째 단계 와 세 번 째 단계 의 순 서 는 보장 할 수 없고 최종 집행 순 서 는 1-2-3 일 수도 있 고 1-3-2 일 수도 있다.후자 라면 3 실행 이 끝나 고 2 가 실행 되 지 않 기 전에 스 레 드 2 에 의 해 선점 되 었 습 니 다.이때 인 스 턴 스 는 이미 null 이 아 닙 니 다(그러나 초기 화 되 지 않 았 습 니 다).그래서 스 레 드 2 는 인 스 턴 스 로 직접 돌아 가서 사용 한 다음 에 순조롭게 오 류 를 보고 합 니 다.이 를 위해 서 는 인 스 턴 스 변 수 를 volatile 로 설명 해 야 합 니 다.
    
    public class Singleton {
     private volatile static Singleton instance; //    volatile
     private Singleton(){}
     public static Singleton getSingleton() {
      if (instance == null) {       
       synchronized (Singleton.class) {
        if (instance == null) {  
         instance = new Singleton();
        }
       }
      }
      return instance;
     } 
    }
    
    그러나 특히 자바 1.5 이전 버 전에 서 volatile 의 쌍 검 자 물 쇠 를 사용 한 것 은 문제 가 있 습 니 다.이 문 제 는 자바 1.5 에서 복 구 될 수 있 기 때문에 그 후에 야 volatile 을 안심 하고 사용 할 수 있 습 니 다.
    정적 내부 클래스:IoDH,initialization-on-demand holder
    이 모델 은 자바 의 정적 내부 클래스 와 다 중 스 레 드 부족 동기 화 잠 금 지식 을 종합 적 으로 사용 하여 로드 지연 과 스 레 드 안전 을 교묘 하 게 동시에 실현 했다.
    
    public class Singleton {
     private Singleton() {}
     private static class LazyHolder {
      private static final Singleton INSTANCE = new Singleton();
     }
     public static Singleton getInstance() {   // From wikipedia
      return LazyHolder.INSTANCE;
     }
    }
    
    정적 내부 클래스 는 외부 클래스 의 static 부분 에 해당 하 며,대상 은 외부 클래스 대상 에 의존 하지 않 기 때문에 직접 만 들 수 있 습 니 다.정적 내부 클래스 는 처음 사 용 될 때 만 전 재 됩 니 다.
    다 중 스 레 드 부족 동기 화 잠 금
    다 중 스 레 드 개발 에서 병발 문 제 를 해결 하기 위해 주로 synchronized 를 사용 하여 상호 배척 자 물 쇠 를 추가 하여 동기 화 통 제 를 하 는 것 을 잘 알 고 있 습 니 다.그러나 어떤 경우 에는 JVM 이 은밀하게 동기 화 를 실 행 했 기 때문에 수 동 으로 동기 화 제 어 를 할 필요 가 없습니다.이러한 상황 은 다음 과 같다.
       1.정적 초기 화기(정적 필드 나 static{}블록의 초기 화기)에서 데 이 터 를 초기 화 할 때
    2.final 필드 에 접근 할 때
    3.스 레 드 를 만 들 기 전에 대상 을 만 들 때
    4.스 레 드 가 처리 할 대상 을 볼 수 있 을 때
    열거 하 다.
    자바 1.5 부터 하나의 요 소 를 포함 하 는 매 거 진 형식 만 작성 하 십시오:
    
    public enum Singleton {
     INSTANCE;
    }
    이런 방법 은 기능 적 으로 공유 역 방법 과 비슷 하지만 더욱 간결 하고 무상 으로 서열 화 메커니즘 을 제공 하여 여러 차례 의 실례 화 를 절대적 으로 방지한다.복잡 한 서열 화 나 반사 공격 을 할 때 도.이런 방법 은 아직 널리 사용 되 지 않 았 지만 단일 요소 의 매 거 진 유형 과 싱글 톤 을 실현 하 는 가장 좋 은 방법 이 되 었 다.
    다음은 몇 가지 세부 적 인 의문 을 제기 하 는 실현 방법 이다.
    1.static final 어떤 디 테 일이 있 는 지
    2.static field 의 할당 초기 화 는 static 코드 블록 과 선후 가 있 습 니까?
    3.정적 내부 클래스 의 단일 모드 를 어떻게 쓰 는 지
    4.P50 in 자바 EE 디자인 모델 분석 과 응용 중의 예 는 정말 Lazyload 효과 가 있 습 니까?
    이상 은 본 고의 모든 내용 입 니 다.본 고의 내용 이 여러분 의 학습 이나 업무 에 어느 정도 도움 이 되 기 를 바 랍 니 다.또한 저 희 를 많이 지지 해 주시 기 바 랍 니 다!

    좋은 웹페이지 즐겨찾기