디자인 모델 - 단일 모델 의 몇 가지 실현 방식

1. 굶 주 린 한식: 정적 상수
이 방법 은 매우 간단 합 니 다. 하나의 인 스 턴 스 가 static 과 final 변수 로 밝 혀 졌 기 때문에 처음으로 메모리 에 클래스 를 불 러 올 때 초기 화 되 기 때문에 인 스 턴 스 자 체 를 만 드 는 것 이 안전 합 니 다.
public class Singleton1 {

	private final static Singleton1 instance = new Singleton1();
	private Singleton1(){}
	public static Singleton1 getInstance(){
		return instance;
	}
}

클 라 이언 트 가 getInstance () 방법 을 호출 하지 않 았 더 라 도 게 으 른 로 딩 이 아 닌 것 이 단점 입 니 다.굶 주 린 사람의 생 성 방식 은 일부 장면 에서 사용 할 수 없습니다. 예 를 들 어 Singleton 인 스 턴 스 의 생 성 은 매개 변수 나 설정 파일 에 의존 합 니 다. getInstance () 전에 특정한 방법 으로 파 라 메 터 를 설정 해 야 합 니 다. 그러면 단일 쓰기 방법 은 사용 할 수 없습니다.
2. 게으름뱅이: 라인 이 안전 하지 않 음
public class Singleton3 {
	
	private static Singleton3 instance ;
	private Singleton3(){}
	public  static Singleton3 getInstance(){
		if(instance == null){
			instance = new Singleton3();
		}
		return instance;
	}
}

게 으 른 로드 모드 를 사 용 했 지만 치 명 적 인 문제 가 있 었 다.여러 스 레 드 가 getInstance () 를 병행 호출 할 때 여러 개의 인 스 턴 스 를 만 듭 니 다. 즉, 다 중 스 레 드 에서 정상적으로 작 동 하지 못 합 니 다.3. 게으름뱅이: 스 레 드 안전
public class Singleton4 {

	private static Singleton4 instance;
	private Singleton4(){}
	public static synchronized Singleton4 getInstance(){
		if(instance == null){
			instance = new Singleton4();
		}
		return instance;
	}
}

비록 스 레 드 가 안전 하고 여러 사례 의 문 제 를 해결 하 였 으 나 효율 적 이지 않다.언제든지 하나의 스 레 드 에서 getInstance () 방법 을 호출 할 수 있 지만 동기 화 작업 은 첫 번 째 호출 때 만 필요 합 니 다. 즉, 첫 번 째 인 스 턴 스 대상 을 만 들 때 만 필요 합 니 다.4. 게으름뱅이 식: 정적 내부 클래스
public class Singleton5 {

	private static class SingletonHandler{
		private static final Singleton5 INSTANCE = new Singleton5();
	}
	private Singleton5(){}
	public static Singleton5 getInstance(){
		return SingletonHandler.INSTANCE;
	}
}

이러한 쓰기 방법 은 JVM 자체 체 제 를 사용 하여 스 레 드 안전 문 제 를 확보 합 니 다.Singleton Handler 는 개인 적 인 것 이기 때문에 getInstacne () 을 제외 하고 접근 할 수 없 기 때문에 게으름뱅이 식 입 니 다.동시에 인 스 턴 스 를 읽 을 때 동기 화 되 지 않 고 성능 결함 이 없 으 며 JDK 버 전에 의존 하지 않 습 니 다.
5. 이중 검사 자물쇠:
이중 검사 모드 는 동기 블록 에 자 물 쇠 를 넣 는 방법 이다.이중 검사 자물쇠 라 고도 부 릅 니 다. 인 스 턴 스 = = null 을 두 번 검사 하기 때 문 입 니 다. 한 번 은 동기 화 블록 밖 에 있 고 한 번 은 동기 화 속도 안에 있 습 니 다.동기 블록 에서 왜 한 번 더 검 사 를 해 야 합 니까? 동기 블록 밖의 if 에 여러 개의 스 레 드 가 함께 들 어 갈 수 있 기 때문에 동기 블록 에서 두 번 검 사 를 하지 않 으 면 여러 개의 인 스 턴 스 가 생 성 됩 니 다.
public class Singleton6 {
	
	private static Singleton6 instance;
	private Singleton6(){}
	public static Singleton6 getSingleton6(){
		if(instance==null){
			synchronized(Singleton6.class){
				if(instance==null){
				   instance = new Singleton6();
				}
			}
		}
		return instance;
	}
	
	
}

그 중에서 intance = new Singleton 6 () 는 원자 조작 이 아니 라 사실상 JVM 에서 이 말 은 세 가지 일 을 했다.
1. instance 에 메모리 할당
2. Singleton 6 의 구조 함 수 를 호출 하여 구성원 변 수 를 초기 화 합 니 다.
3. 인 스 턴 스 대상 을 분 배 된 공간 으로 가리 키 기 (이 단 계 를 실행 하면 인 스 턴 스 는 null)
그러나 JVM 의 인 스 턴 트 컴 파일 러 에 명령 재 정렬 의 최적화 가 존재 한다. 즉, 위의 두 번 째 단계 와 세 번 째 단 계 는 순 서 를 보장 할 수 없고 최종 집행 순 서 는 1 - 2 - 3 또는 1 - 3 - 2 일 수 있다.후자 라면 3 실행 이 완료 되 고 2 실행 전에 스 레 드 2 에 의 해 선점 되 었 습 니 다. 이때 인 스 턴 스 는 이미 null 이 아 닙 니 다 (그러나 초기 화 되 지 않 았 습 니 다). 그래서 스 레 드 2 는 인 스 턴 스 로 직접 돌아 가서 사용 한 다음 에 잘못 보고 합 니 다.
public class Singleton6 {
	
	private volatile static Singleton6 instance;
	private Singleton6(){}
	public static Singleton6 getSingleton6(){
		if(instance==null){
			synchronized(Singleton6.class){
				if(instance==null){
				   instance = new Singleton6();
				}
			}
		}
		return instance;
	}
	
	
}

volatile 을 사용 하 는 이 유 는 가시 성 때 문 이 라 고 생각 합 니 다. 즉, 스 레 드 가 로 컬 에 인 스 턴 스 복사 본 이 저장 되 지 않도록 보장 할 수 있 습 니 다. 매번 메 인 메모리 에서 읽 지만 사실은 그렇지 않 습 니 다.volatile 을 사용 하 는 주요 원인 은 또 다른 특성 이다. 명령 재 정렬 최적화 금지.즉, volatile 변수의 할당 작업 뒤에 메모리 장벽 (생 성 된 어 셈 블 리 코드) 이 있 고 읽 기 동작 은 메모리 장벽 이전 으로 정렬 되 지 않 습 니 다.예 를 들 어 위의 예 에서 추출 작업 은 1 - 2 - 3 을 실행 한 후에 또는 1 - 3 - 2 를 실행 한 후에 1 - 3 을 실행 한 후에 값 을 얻 는 상황 이 존재 하지 않 습 니 다.[선행 발생 원칙] 의 측면 에서 이해 하면 하나의 volatile 변수 에 대한 쓰기 동작 은 모두 뒤에서 이 변수 에 대한 읽 기 동작 에서 먼저 발생 하 는 것 이다.
메모: 자바 5 이전 버 전에 서 volatile 의 더 블 검사 자 물 쇠 를 사용 한 것 은 문제 가 있 습 니 다.그 이 유 는 자바 5 이전의 JMM (자바 메모리 모델) 에 결함 이 있 기 때문에 변 수 를 volatile 로 즉시 설명 해도 정렬 을 피 할 수 없 기 때문이다.
6. 매 거:
public class Singleton7 {

	public enum EasySingleton{
		INSTANCE;
	}
}

Easy Singleton. INSTANCE 를 통 해 인 스 턴 스 를 방문 할 수 있 습 니 다. 이것 은 getInstance () 를 호출 하 는 방법 보다 훨씬 간단 합 니 다.매 거 진 기본 값 을 만 드 는 것 은 스 레 드 안전 이 며, 반 직렬 화 로 인해 새로운 대상 을 다시 만 드 는 것 을 방지 할 수 있 습 니 다.

좋은 웹페이지 즐겨찾기