자바 Volatile 응용 단일 모드 구현 프로 세 스 분석

단일 모드
단선 에서 의 단일 모드 코드 를 돌 이 켜 보 세 요.
굶 주 린 사람 식
  • 구조 기 민영화
  • 자체 적 으로 만 들 고 정적 변수 로 static
  • 을 저장 합 니 다.
  • 이 인 스 턴 스 Public
  • 를 외부 에 제공 합 니 다.
  • 이것 은 하나의 사례 라 고 강조 하고 final
  • 
    public class sington(){
      public final static INSTANCE = new singleton();
      private singleton(){}
    }
    두 번 째:jdk 1.5 이후 매 거 진 형식 으로
    매 거 유형:이 유형의 대상 이 유한 하 다 는 것 을 나타 내 는 몇 가지 유형
    우 리 는 한 개 로 한정 할 수 있 는데,단 례 라 고 부른다
    
    public enum Singleto{
      INSTANCE
    }
    세 번 째 정적 코드 블록
    
    public class Singleton{
    public final static INSTANCE;
    static{
      INSTANCE = new Singleton();
    }
    private Singleton(){}
    
    }
    게으름뱅이 구조 기 민영화
    이 유일한 인 스 턴 스 를 정적 변수 로 저장 합 니 다.
    이 인 스 턴 스 를 가 져 오 는 정적 방법 을 제공 합 니 다.
    
    public class Singleton{
      private static Singleton INSTANCE;
      private Singleton(){}
      public static Singleton getInstance(){
        if(instance==null){
          INSTANCE = new Singleton();
        }
        return INSTANCE;
      }
    }
    
    public class SingletonDemo {
    
      private static SingletonDemo instance = null;
    
      private SingletonDemo () {
        System.out.println(Thread.currentThread().getName() + "\t       SingletonDemo");
      }
    
      public static SingletonDemo getInstance() {
        if(instance == null) {
          instance = new SingletonDemo();
        }
        return instance;
      }
    
      public static void main(String[] args) {
        //     ==        
        System.out.println(SingletonDemo.getInstance() == SingletonDemo.getInstance());
        System.out.println(SingletonDemo.getInstance() == SingletonDemo.getInstance());
        System.out.println(SingletonDemo.getInstance() == SingletonDemo.getInstance());
        System.out.println(SingletonDemo.getInstance() == SingletonDemo.getInstance());
      }
    }
    마지막 출력 결과:

    그러나 다 중 스 레 드 환경 에서 우리 의 단일 모델 은 같은 대상 입 니까?
    
    public class SingletonDemo {
    
      private static SingletonDemo instance = null;
    
      private SingletonDemo () {
        System.out.println(Thread.currentThread().getName() + "\t       SingletonDemo");
      }
    
      public static SingletonDemo getInstance() {
        if(instance == null) {
          instance = new SingletonDemo();
        }
        return instance;
      }
    
      public static void main(String[] args) {
        for (int i = 0; i < 10; i++) {
          new Thread(() -> {
            SingletonDemo.getInstance();
          }, String.valueOf(i)).start();
        }
      }
    }
    아래 의 결 과 를 통 해 알 수 있 듯 이 우 리 는 Singleton Demo.getInstance()를 통 해 얻 은 대상 은 같은 것 이 아니 라 아래 의 몇 개의 스 레 드 에 의 해 만들어 진 것 입 니 다.그러면 다 중 스 레 드 환경 에서 단일 모델 은 어떻게 보장 합 니까?

    해결 방법
    synchronized 키워드 도입
    
    public synchronized static SingletonDemo getInstance() {
      if(instance == null) {
        instance = new SingletonDemo();
      }
      return instance;
    }
    출력 결과:

    Synchronized 키 워드 를 도입 함으로써 높 은 병발 환경 에서 의 단일 모델 문 제 를 해결 할 수 있 음 을 알 수 있 습 니 다.
    그러나 synchronized 는 중량급 동기 화 체제 로 하나의 스 레 드 만 동시에 방문 하여 인 스 턴 스 를 얻 는 방법 을 허용 하지만 데이터 의 일치 성 을 확보 하기 위해 동시성 을 낮 추 었 기 때문에 사용 하 는 것 이 비교적 적다.
    해결 방법
    DCL Double Check Lock 양단 잠 금 메커니즘 도입 을 통 해
    
      public static SingletonDemo getInstance() {
        if(instance == null) {
          //         ,    
          synchronized (SingletonDemo.class) {
            if(instance == null) {
              instance = new SingletonDemo();
            }
          }
        }
        return instance;
      }
    마지막 출력 결 과 는:

    출력 결 과 를 보면 단일 모델 의 정확성 을 확보 할 수 있 지만 위의 방법 에는 문제 가 존재 한다.
    DCL(양단 검 쇄)메커니즘 이 반드시 라인 이 안전 한 것 은 아니다.왜냐하면 지령 재배 열 이 존재 하기 때문이다.volatile 에 가입 하면 지령 재배 열 을 금지 할 수 있다
    이 유 는 한 스 레 드 가 첫 번 째 검 측 을 실 행 했 을 때 인 스 턴 스 가 null 이 아 닌 것 을 읽 었 기 때 문 입 니 다.인 스 턴 스 의 참조 대상 이 실례 화 되 지 않 았 을 수도 있 습 니 다.왜냐하면 instance=new SingletonDemo();다음 세 단계 로 나 누 어 완성 할 수 있 습 니 다.
  • memory = allocate(); // 1.할당 대상 메모리 공간
  • instance(memory); // 2.대상 초기 화
  • instance = memory; // 3.instance 가 방금 분 배 된 메모리 주 소 를 가리 키 도록 설정 합 니 다.이때 instance!=null
  • 그러나 우 리 는 위의 세 가지 절 차 를 통 해 절차 2 와 절차 3 사이 에 데이터 의존 관계 가 존재 하지 않 는 다 는 것 을 알 수 있다.또한 재배 치 전이 든 재배 치 후 든 프로그램의 실행 결 과 는 단일 스 레 드 에서 변 하지 않 았 기 때문에 이런 재배 치 최적화 가 허용 된다.
  • memory = allocate(); // 1.할당 대상 메모리 공간
  • instance = memory; // 3.instance 가 방금 분 배 된 메모리 주 소 를 가리 키 도록 설정 합 니 다.이때 instance!=null,하지만 대상 이 초기 화 되 지 않 았 습 니 다
  • instance(memory); // 2.대상 초기 화
  • 이렇게 하면 어떤 문제 가 생 길 까요?
    즉,리 셋 후 단계 2 를 실행 하고 인 스 턴 스 를 가 져 오 려 고 할 때 null 을 얻 을 수 있 습 니 다.대상 의 초기 화가 완료 되 지 않 았 고 리 셋 후 단계 3 이 완성 되 었 기 때문에 단일 모드 의 코드 를 실행 할 때 인 스 턴 스 인 스 턴 스 인 스 턴 스 를 다시 만 듭 니 다.
    명령 정렬 은 직렬 의미 의 집행 일치 성(단일 스 레 드)만 보장 하지만 다 중 스 레 드 간 의 의미 일치 성 은 관계 되 지 않 습 니 다.
    따라서 하나의 스 레 드 가 intance 에 접근 하지 않 을 때 intance 인 스 턴 스 가 초기 화 되 지 않 았 기 때문에 스 레 드 안전 에 문제 가 생 겼 습 니 다.
    따라서 volatile 을 도입 하여 명령 재배 치 문제 가 발생 하도록 하고 단일 모델 의 스 레 드 안전성 을 확보 해 야 한다.
    private static volatile SingletonDemo instance = null;
    최종 코드
    
    public class SingletonDemo {
    
      private static volatile SingletonDemo instance = null;
    
      private SingletonDemo () {
        System.out.println(Thread.currentThread().getName() + "\t       SingletonDemo");
      }
    
      public static SingletonDemo getInstance() {
        if(instance == null) {
          // a                            ,             d 
          synchronized (SingletonDemo.class) //b
          { 
          //c  volitale                         。             
            if(instance == null) { 
            	// d         
              instance = new SingletonDemo();
            }
          }
        }
        return instance;
      }
    
      public static void main(String[] args) {
    //    //     ==        
    //    System.out.println(SingletonDemo.getInstance() == SingletonDemo.getInstance());
    //    System.out.println(SingletonDemo.getInstance() == SingletonDemo.getInstance());
    //    System.out.println(SingletonDemo.getInstance() == SingletonDemo.getInstance());
    //    System.out.println(SingletonDemo.getInstance() == SingletonDemo.getInstance());
    
        for (int i = 0; i < 10; i++) {
          new Thread(() -> {
            SingletonDemo.getInstance();
          }, String.valueOf(i)).start();
        }
      }
    }
    이상 이 바로 본 고의 모든 내용 입 니 다.여러분 의 학습 에 도움 이 되 고 저 희 를 많이 응원 해 주 셨 으 면 좋 겠 습 니 다.

    좋은 웹페이지 즐겨찾기