JAVA 단일 모드를 실현하는 네 가지 방법과 특징
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)에 적용됩니다.기초 유형이 구조 함수를 호출하지 않았기 때문에 분명하다.
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
JAVA 객체 작성 및 제거 방법정적 공장 방법 정적 공장 방법의 장점 를 반환할 수 있습니다. 정적 공장 방법의 단점 류 공유되거나 보호된 구조기를 포함하지 않으면 이불류화할 수 없음 여러 개의 구조기 파라미터를 만났을 때 구축기를 고려해야 한다...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.