자바 단일 모드 의 8 가지 쓰기(추천)

11101 단어 Java단일 모드
단일 예:Singleton 은 한 번 만 실례 화 된 종 류 를 말한다.
굶 주 린 한 사례 디자인 모델
1.굶 주 린 남자 디자인 모델

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

 private SingletonHungry() {
 }

 public static SingletonHungry getInstance() {
 return INSTANCE;
 }
}
단일 대상 이 처음부터 초기 화 되 었 기 때문에 스 레 드 안전 에 문제 가 생기 지 않 습 니 다.
PS:우 리 는 1 회 만 초기 화 할 수 있 기 때문에 INSTANCE 에final키 워드 를 추가 하여 1 회 초기 화 후 초기 화 를 허용 하지 않 음 을 표시 합 니 다.
게으름뱅이 단일 디자인 모델
2.단순 게으름뱅이 디자인 모델
굶 주 린 사람 모드 는 처음부터 초기 화 되 었 지만 계속 사용 되 지 않 으 면 소중 한 메모리 자원 을 낭비 할 수 있 기 때문에 게 으 른 사람 모드 를 이 끌 어 냈 다.
게으름뱅이:처음 사용 할 때 만 대상 을 예화 합 니 다.

public class SingletonLazy1 {
 private static SingletonLazy1 instance;

 private SingletonLazy1() {
 }

 public static SingletonLazy1 getInstance() {
 if (instance == null) {
  instance = new SingletonLazy1();
 }
 return instance;
 }
}
테스트:

public class Main {
 public static void main(String[] args) {
 SingletonLazy1 instance1 = SingletonLazy1.getInstance();
 SingletonLazy1 instance2 = SingletonLazy1.getInstance();
 System.out.println(instance1);
 System.out.println(instance2);
 }
}
테스트 결과:결과 에서 알 수 있 듯 이 인쇄 된 두 개의 인 스 턴 스 대상 주 소 는 같 기 때문에 하나의 대상 만 만 만 들 었 다 고 생각 합 니 다.
在这里插入图片描述
3.진급
1:다 중 스 레 드 병행 문제 해결
상기 코드 에 존재 하 는 문제점:다 중 스 레 드 환경 에서 하나의 인 스 턴 스 만 만 들 수 없습니다.우 리 는 문제 의 재현 을 진행 합 니 다.

public class Main {
 public static void main(String[] args) {
 new Thread(()-> System.out.println(SingletonLazy1.getInstance())).start();
 new Thread(()-> System.out.println(SingletonLazy1.getInstance())).start();
 }
}
결과:얻 은 대상 이 다 릅 니 다.이것 은 우리 가 예상 한 결과 가 아 닙 니 다.
在这里插入图片描述
해결 방안:

public class SingletonLazy2 {
 private static SingletonLazy2 instance;

 private SingletonLazy2() {
 }
 //    synchronized   
 public static synchronized SingletonLazy2 getInstance() {
 if (instance == null) {
  instance = new SingletonLazy2();
 }
 return instance;
 }
}
테스트:

public class Main2 {
 public static void main(String[] args) {
 new Thread(()-> System.out.println(SingletonLazy2.getInstance())).start();
 new Thread(()-> System.out.println(SingletonLazy2.getInstance())).start();
 new Thread(()-> System.out.println(SingletonLazy2.getInstance())).start();
 new Thread(()-> System.out.println(SingletonLazy2.getInstance())).start();
 }
}
在这里插入图片描述
결과:다 중 스 레 드 환경 에서 같은 대상 을 얻 었 습 니 다.
4.진급 2:축소 방법 잠 금 입도
이전 방안 은 다 중 스 레 드 문 제 를 해결 하 였 으 나 synchronized 키 워드 는 방법 에 추 가 된 것 이기 때문에 잠 금 입도 가 매우 크 고 수만,심지어 더 많은 스 레 드 가 동시에 방문 할 때 방법 밖 에 막 혀 프로그램의 성능 을 크게 떨 어 뜨 렸 기 때문에 우 리 는 잠 금 입 도 를 적당 하 게 줄 이 고 잠 금 의 범 위 를 코드 블록 에 제어 해 야 한다.

public class SingletonLazy3 {
 private static SingletonLazy3 instance;

 private SingletonLazy3() {
 }
 
 public static SingletonLazy3 getInstance() {
 //   1:   if   ,           
 if (instance == null) {
  //   2:  ,          
  synchronized (SingletonLazy3.class) {
  //   3
  instance = new SingletonLazy3();
  }
 }
 return instance;
 }
}
테스트:

public class Main3 {
 public static void main(String[] args) {
 new Thread(()-> System.out.println(SingletonLazy3.getInstance())).start();
 new Thread(()-> System.out.println(SingletonLazy3.getInstance())).start();
 new Thread(()-> System.out.println(SingletonLazy3.getInstance())).start();
 new Thread(()-> System.out.println(SingletonLazy3.getInstance())).start();
 }
}
실행 결 과 를 살 펴 보 겠 습 니 다.아니면 스 레 드 안전 에 문제 가 생 겼 습 니까?
在这里插入图片描述
원인 분석:스 레 드 A 가 자 물 쇠 를 가 져 와 3에 들 어가 고 인 스 턴 스 를 만 들 지 않 았 을 때 스 레 드 B 는 도착 할 기회 가 있 습 니 다 2.이때 스 레 드 C 와 D 는 1에 있 을 수 있 습 니 다.스 레 드 A 가 실 행 된 후에 자 물 쇠 를 풀 고 대상 1 로 돌아 갑 니 다.스 레 드 B 가 들 어가 3새로운 대상 2 커버 대상 1 을 만 들 고 돌아 갑 니 다.마지막 으로 스 레 드 C 와 D 가 null 을 판단 할 때 인 스 턴 스 가 비어 있 지 않 은 것 을 발견 하고 마지막 으로 만 든 대상 2 를 되 돌려 줍 니 다.
5.진급 3:잠 금 DCL 이중 검사(Double-Checked-Locking)
이중 검사 자물쇠 란 스 레 드 에서 자 물 쇠 를 가 져 온 후에 인 스 턴 스 를 두 번 째 로 빈 칸 으로 검사 하 는 것 입 니 다.이전 스 레 드 가 이미 예화 되 었 는 지 판단 하고 있 으 면 바로 돌아 가면 됩 니 다.그렇지 않 으 면 인 스 턴 스 를 초기 화 합 니 다.

public class SingletonLazy4DCL {
 private static SingletonLazy4DCL instance;

 private SingletonLazy4DCL() {
 }

 public static SingletonLazy4DCL getInstance() {
 //   1:       
 if (instance == null) {
  //   2:  ,          
  synchronized (SingletonLazy3.class) {
  //   3:     (  )    
  if (instance == null) {
   instance = new SingletonLazy4DCL();
  }
  }
 }
 return instance;
 }
}
테스트:

public class Main4DCL {
 public static void main(String[] args) {
 new Thread(()-> System.out.println(SingletonLazy4DCL.getInstance())).start();
 new Thread(()-> System.out.println(SingletonLazy4DCL.getInstance())).start();
 new Thread(()-> System.out.println(SingletonLazy4DCL.getInstance())).start();
 new Thread(()-> System.out.println(SingletonLazy4DCL.getInstance())).start();
 }
}
在这里插入图片描述
6,진급 4:명령 정렬 금지
대상 의 인 스 턴 스 과정 에서 다음 과 같은 세 단계 로 나 눌 수 있 습 니 다.
  • 분배 대상 메모리 공간
  • 공간 에서 대상 만 들 기
  • 인 스 턴 스 는 분 배 된 메모리 공간 주 소 를 가리킨다
  • 실례 화 대상 의 과정 이 원자 적 이지 않 고 JVM 자체 가 자바 코드 명령 에 대해 재배 열 하 는 작업 이 있 기 때문에 1-2-3 의 작업 이 1-3-2 로 재 정렬 될 수 있 습 니 다.그러면 3 이 실 행 된 후에 대상 을 만 들 지 못 했 을 때 다른 스 레 드 가 초기 화 되 지 않 은 대상 인 스 턴 스 를 먼저 읽 고 미리 되 돌아 갈 수 있 습 니 다.사용 할 때 NPE 빈 포인터 이상 이 발생 할 수 있 습 니 다.
    해결:instance 에volatile키 워드 를 추가 하면 명령 을 다시 배열 하 는 것 을 금지 하고 나타 날 확률 이 크 지 않 지만 이것 은 더욱 안전 한 방법 입 니 다.
    
    public class SingletonLazy5Volatile {
     // volatile   
     private volatile static SingletonLazy5Volatile instance;
    
     private SingletonLazy5Volatile() {
     }
    
     public static SingletonLazy5Volatile getInstance() {
     //   1
     if (instance == null) {
      //   2:  ,          
      synchronized (SingletonLazy3.class) {
      //   3
      if (instance == null) {
       instance = new SingletonLazy5Volatile();
      }
      }
     }
     return instance;
     }
    }
    7.진급 5:정적 내부 클래스
    정적 클래스 의 정적 변 수 를 사용 하여 첫 번 째 방문 시 초기 화 할 수 있 습 니 다.외부 클래스 의 단일 대상 을 정적 내부 클래스 의 정적 구성원 변수 에 넣 어 초기 화 합 니 다.
    
    public class SingletonLazy6InnerStaticClass {
     private SingletonLazy6InnerStaticClass() {
     }
    
     public static SingletonLazy6InnerStaticClass getInstance() {
     return SingletonLazy6InnerStaticClass.InnerStaticClass.instance;
     //    return InnerStaticClass.instance;
     }
    
     private static class InnerStaticClass {
     private static final SingletonLazy6InnerStaticClass instance = new SingletonLazy6InnerStaticClass();
     }
    }
    정적 내부 클래스 의 쓰기 방식 은 굶 주 린 사람 모드 와 비슷 하지만 외부 클래스 가 불 러 올 때 초기 화 되 는 것 이 아니 라 처음 방문 할 때 초기 화 되 는 작업(즉 getInstance 방법 이 호출 될 때)도 게 으 른 로 딩 효 과 를 내 고 스 레 드 안전 을 확보 할 수 있 습 니 다.
    테스트:
    
    public class Main6InnerStatic {
     public static void main(String[] args) {
     new Thread(()-> System.out.println(SingletonLazy6InnerStaticClass.getInstance())).start();
     new Thread(()-> System.out.println(SingletonLazy6InnerStaticClass.getInstance())).start();
     new Thread(()-> System.out.println(SingletonLazy6InnerStaticClass.getInstance())).start();
     new Thread(()-> System.out.println(SingletonLazy6InnerStaticClass.getInstance())).start();
     }
    }
    在这里插入图片描述
    반사 공격
    비록 우 리 는 처음에 구조 기 를 사유 화 처 리 했 지만 자바 자체 의 반사 체 제 는 private 방문 권한 을 방문 가능 으로 바 꿀 수 있 고 새로운 인 스 턴 스 대상 을 만 들 수 있 습 니 다.여 기 는 굶 주 린 사람 모델 로 예 를 들 어 설명 합 니 다.
    
    public class MainReflectAttack {
     public static void main(String[] args) {
     try {
      SingletonHungry normal1 = SingletonHungry.getInstance();
      SingletonHungry normal2 = SingletonHungry.getInstance();
      //        
      Constructor<SingletonHungry> reflect = SingletonHungry.class.getDeclaredConstructor(null);
      reflect.setAccessible(true);
      SingletonHungry attack = reflect.newInstance();
      
      System.out.println("              :");
      System.out.println(normal1);
      System.out.println(normal2);
      System.out.println("        :");
      System.out.println(attack);
     } catch (Exception e) {
      e.printStackTrace();
     }
     }
    }
    在这里插入图片描述
    8.매 거 사례(추천 사용)
    
    public enum SingletonEnum {
     INSTANCE;
    }
    매 거 진 것 은 가장 간결 하고 스 레 드 가 안전 하 며 반사 되 지 않 고 인 스 턴 스 를 만 드 는 단일 사례 로 이 루어 집 니 다.에서 도 이러한 기법 이 가장 좋 은 단일 사례 실현 모델 임 을 나 타 냈 습 니 다.
    단일 요소 의 매 거 유형 은 항상 싱글 턴 을 실현 하 는 가장 좋 은 방법 이 된다.-'Effective Java》
    왜 반사 되 지 않 고 대상 을 만든다 고 하 죠?구조 기 반사 실례 화 대상 방법newInstance의 원본 코드 를 보면 알 수 있 듯 이 반사 가 매 거 진 대상 의 실례 화 를 금지 하고 반사 공격 을 방지 하 며 스스로 구조 기 에서 복잡 한 중복 실례 화 논 리 를 실현 하지 않 아 도 된다.
    在这里插入图片描述
    테스트:
    
    public class MainEnum {
     public static void main(String[] args) {
     SingletonEnum instance1 = SingletonEnum.INSTANCE;
     SingletonEnum instance2 = SingletonEnum.INSTANCE;
     System.out.println(instance1.hashCode());
     System.out.println(instance2.hashCode());
     }
    }
    在这里插入图片描述
    결론:몇 가지 실현 방식 의 장단 점 게으름뱅이 모델
    장점:메모리 절약.
    단점:스 레 드 안전 문제 가 존재 합 니 다.스 레 드 안전 을 확보 하려 면 쓰기 가 복잡 합 니 다.
    굶 주 린 남자 모델
    장점:스 레 드 안전.
    단점:단일 대상 이 계속 사용 되 지 않 으 면 메모리 공간 이 낭비 된다.
    정적 내부 클래스
    장점:게 으 름 을 피 우 고 다 중 스 레 드 문 제 를 피 할 수 있 습 니 다.게 으 른 사람 보다 쓰기 가 더 간단 합 니 다.
    단점:내부 클래스 를 하나 더 만들어 야 합 니 다.
    매 거
    장점:간결 하고 타고 난 스 레 드 가 안전 하 며 반사 적 으로 인 스 턴 스 를 만 들 수 없습니다.
    단점:없 음
    자바 단일 모드 에 관 한 8 가지 문법 에 관 한 이 글 은 여기까지 소개 되 었 습 니 다.더 많은 자바 단일 모드 내용 은 우리 의 이전 글 을 검색 하거나 아래 의 관련 글 을 계속 조회 하 시기 바 랍 니 다.앞으로 많은 응원 바 랍 니 다!

    좋은 웹페이지 즐겨찾기