JAVA 단일 모드를 실현하는 네 가지 방법과 특징

3747 단어 JAVA단일 모드
1. 굶주림

public class Singleton 

    private Singleton(){ 

    } 

    private static Singleton instance = new Singleton(); 

    private static Singleton getInstance(){ 
        return instance; 
    } 
특징: 굶주림식 조기 실례화, 게으름뱅이식 다중 스레드 문제는 없지만 getInstance () 를 호출하든 안 하든 메모리에 실례가 존재합니다
2. 내부 클래스

public class Singleton    
{       
        private Singleton(){    

    }    

    private class SingletonHoledr(){    
        private static Singleton instance = new Singleton();    
    }    

    private static Singleton getInstance(){    
        return SingletonHoledr.instance;    
    }    
}
특징: 내부 클래스에서 지연 로딩을 실현하고 getInstance () 를 호출해야만 유일한 실례를 메모리에 만들 수 있습니다.게으름뱅이식 다중 스레드 문제도 해결했다.해결 방법은 Classloader의 특성을 이용하는 것이다.
3. 게으름뱅이

public class Singleton    
{       
    private Singleton(){    

    }    

    private static Singleton instance;    
    public static Singleton getInstance(){    
        if(instance == null){    
            return instance = new Singleton();    
        }else{    
            return instance;    
        }    
    }    
}  
특징: 게으름뱅이식에서 라인 A와 B가 있는데 라인 A가 8줄까지 운행할 때 라인 B로 뛰어들고 B도 8줄까지 운행할 때 두 라인의 instance가 비어 두 개의 실례를 생성한다.해결 방법은 동기화:
동기화는 가능하지만 효율성은 낮습니다.

public class Singleton    
{       
    private Singleton(){    

    }    

    private static Singleton instance;    
    public static synchronized Singleton getInstance(){    
        if(instance == null){    
            return instance = new Singleton();    
        }else{    
            return instance;    
        }    
    }    
}
이렇게 프로그램을 쓰는 것은 오류가 발생하지 않습니다. 왜냐하면 전체 get Instance는 전체적인'critical section'이기 때문입니다. 그러나 효율이 매우 좋지 않습니다. 왜냐하면 우리의 목적은 첫 번째 instance를 초기화할 때locking(잠금장치)이 필요하고 뒤에서 instance를 사용할 때 루트 동기화가 필요하지 않기 때문입니다.
그래서 똑똑한 사람들은 다음과 같은 방법을 생각해 냈다.
이중 자물쇠 쓰기 검사:

public class Singleton{ 
  private static Singleton single;    //  
  private Singleton(){}    //   

  public static Singleton getSingle(){    //    
    if(single == null){    
        synchronized (Singleton.class) {   //        
            if(single == null){     
                single = new Singleton();         
        }    
      } 
    }   
    return single;   //   
  } 
사고방식은 매우 간단하다. 바로 우리가 동기화(synchronize)를 통해 instance의 일부 코드를 초기화하여 코드를 정확하고 효율적으로 만드는 것이다.이것이 바로 이른바'쌍검쇄'메커니즘이다.안타깝게도 이런 작법은 많은 플랫폼과 최적화 컴파일러에서 잘못된 것이다.
원인은 instance = new Singleton () 이 행 코드가 다른 컴파일러에서 어떤 행동을 하는지 예측할 수 없기 때문이다.최적화 컴파일러는 다음과 같이 instance = new Singleton () 을 합법적으로 구현할 수 있습니다.
1. instance = 새 엔티티에 메모리 할당
2. Singleton의 구조 함수를 호출하여 instance의 구성원 변수를 초기화합니다.
이제 get Instance를 호출하는 스레드 A와 B가 있다고 상상해 보세요. 스레드 A가 먼저 들어가서 1단계까지 실행할 때 cpu에서 쫓겨났어요.그리고 스레드 B가 들어왔습니다. B는 instance가 null이 아니라는 것을 보았습니다. (메모리가 분배되었습니다) 그래서 instance를 안심하고 사용하기 시작했습니다. 그러나 이것은 잘못된 것입니다. 왜냐하면 이 순간에 instance의 구성원 변수는 모두 부족한 값이기 때문에 A는 2단계를 실행하지 못해서 instance의 초기화를 완성했습니다.
물론 컴파일러도 이렇게 할 수 있다.
1.temp = 메모리 할당
2.temp의 구조 함수 호출
3. instance = temp
만약 컴파일러의 행동이 이렇다면 우리는 문제가 없을 것 같지만, 사실은 그렇게 간단하지 않다. 왜냐하면 우리는 어떤 컴파일러가 구체적으로 어떻게 하는지 알 수 없기 때문이다. 왜냐하면 자바의 메모리 모델에서 이 문제에 대해 정의가 없기 때문이다.
이중 자물쇠는 기본 형식(예를 들어 int)에 적용됩니다.기초 유형이 구조 함수를 호출하지 않았기 때문에 분명하다.

좋은 웹페이지 즐겨찾기