싱글 톤 모드 와 더 블 검색 잠 금 (DCL)
처음부터 말 해 봐.
다 중 스 레 드 의 경우 Singleton 모드 에서 많은 문제 가 발생 할 수 있 습 니 다. 간단 한 예 입 니 다.
class Singleton {
private static Singleton instance = null;
public static Singleton instance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
이러한 장면 을 가정 하면 두 개의 스 레 드 가 Singleton. intance () 를 호출 합 니 다. 먼저 스 레 드 는 intance 가 null 인지 여 부 를 판단 합 니 다. 판단 이 끝 난 후 한 순간 에 가상 컴퓨터 는 스 레 드 2 를 실행 스 레 드 로 조정 하고 스 레 드 2 는 intance 가 null 인지 다시 판단 한 다음 에 Singleton 인 스 턴 스 를 만 듭 니 다. 스 레 드 2 의 시간 영화 가 다 쓴 후에 스 레 드 가 깨 어 납 니 다.다음 에 실 행 된 코드 는 여전히 instance = new Singleton () 입 니 다.
두 번 의 호출 이 서로 다른 대상 으로 되 돌아 와 문제 가 생 겼 다.
가장 쉬 운 방법 은 클래스 가 불 러 올 때 이 대상 을 초기 화 하 는 것 입 니 다. private static Singleton instance = new Singleton ();
JLS (Java Language Specification) 에 서 는 클래스 가 한 번 만 초기 화 될 수 있 도록 규정 되 어 있 기 때문에 이렇게 하 는 것 은 틀림없이 문제 가 없 을 것 이다.
그러나 지연 초기 화 (Lazy initialization) 를 실현 하려 면 이 인 스 턴 스 초기 화 시의 매개 변 수 는 런 타임 에 확인 해 야 합 니 다. 어떻게 해 야 합 니까?
여전히 가장 간단 한 방법 이 있 습 니 다. synchronized 키 워드 를 사용 하여 초기 화 하 는 방법:
public synchronized static Singleton instance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
여기에 성능 문제 가 하나 있 습 니 다. 여러 스 레 드 가 동시에 이 방법 에 접근 할 때 동기 화로 인해 매번 한 스 레 드 만 실행 되 고 프로그램의 성능 에 영향 을 줄 수 있 습 니 다.사실 초기 화 완료 후 인 스 턴 스 의 인용 을 간단하게 되 돌려 주면 됩 니 다.
DCL 은 '보기' 의 효과 적 인 해결 방법 입 니 다. 먼저 대응 코드 를 올 려 놓 으 세 요.
class Singleton {
private static Singleton instance = null ;
public static Singleton instance() {
if (instance == null ) {
synchronized (this) {
if (instance == null)
instance = new Singleton();
}
}
return instance;
}
}
자바 월 드 에 해당 하 는 글 의 제목 으로 논평 하 는 것 이 스마트, but broken 이다.원인 보기:
자바 컴 파 일 러 는 프로그램의 성능 을 향상 시 키 기 위해 명령 스케줄 링 을 한다. CPU 는 명령 을 실행 할 때 도 마찬가지 로 성능 에 따라 무질서 하 게 실행 된다 (적어도 현재 사용 하고 있 는 대부분의 유 니 버 설 프로 세 서 는 out - of - order). 또한 cache 의 존재 도 데 이 터 를 메모리 에 다시 쓸 때의 순 서 를 바꾼다 [2].JMM (Java Memory Model, [1] 참조) 은 이러한 모든 최적화 가 허용 된다 고 지적 했다. 실행 결과 가 엄격하게 순서대로 실 행 된 결과 와 같 으 면 된다.
자바 는 모든 스 레 드 가 자신의 프로세서 에 달 려 자신의 메모리 와 공 유 된 메 인 저장 소 와 상호작용 을 한다 고 가정 합 니 다.단일 핵 에서 도 이 모델 은 의미 가 있 으 며, cache 와 레지스터 를 고려 하여 일부 임시 변 수 를 저장 합 니 다.이론 적 으로 모든 스 레 드 가 자신의 메모 리 를 수정 한 후에 반드시 해당 하 는 메 인 저장 내용 을 즉시 업데이트 해 야 한다.그러나 자바 디자이너 들 은 이러한 제약 이 프로그램의 성능 에 영향 을 줄 것 이 라 고 생각한다. 그들 은 프로그램 을 더욱 빨리 달리 게 하지만 스 레 드 간 의 상호작용 과 예상 과 일치 하 는 메모리 모델 을 만 들 려 고 한다.
synchronized 키 워드 는 바로 그 중의 이기 입 니 다.사실 synchronized 블록 의 실현 은 Linux 의 신 호 량 (semaphore) 과 차이 가 있 습 니 다. 전자 과정 에서 잠 금 의 획득 과 방출 은 Memory Barrier 를 통 해 로 컬 메모리 와 메 인 메모리 간 의 동기 화 를 강제 합 니 다.이 메커니즘 을 통 해 자바 의 동기 화 메커니즘 은 synchronized 블록 에서 명령 한 원자 성 (atomic) 을 확보 했다.
자, 돌 이 켜 보면 DCL 문제.동기 화 되 지 않 은 인 스 턴 스 필드 에 접근 하 는 데 문제 가 없 을 것 같 습 니 다. 한 장면 을 다시 가정 해 보 겠 습 니 다.
스 레 드 가 동기 화 블록 에 들 어가 면 instance = new Singleton () 을 실행 합 니 다.스 레 드 2 가 getResource () 를 처음 실행 합 니 다.
순서대로 다음 에 실행 해 야 할 절 차 는 1) 새로운 Singleton 대상 의 메모리 2) 를 할당 하여 Singleton 의 구조 기 를 호출 하고 구성원 필드 를 초기 화 하 는 것 입 니 다. 3) intance 는 새로운 대상 을 가리 키 는 참조 로 부 여 됩 니 다.
앞에서 말 했 듯 이 컴 파일 러 나 프로세서 가 성능 을 향상 시 키 기 위해 명령 의 난 서 를 실행 할 수 있 습 니 다. 스 레 드 1 의 실제 실행 절 차 는 1) 메모리 할당 2) intance 가 새로운 대상 3) 을 가리 키 며 새로운 인 스 턴 스 를 초기 화 할 수 있 습 니 다.스 레 드 2 가 2 가 완 료 된 후 3 이 실행 되 기 전에 깨 어 나 면 null 이 아 닌 인 스 턴 스 를 보 았 습 니 다. 방법 체 를 뛰 어 내 려 초기 화 되 지 않 은 Singleton 대상 을 가지 고 있 습 니 다.
오류 가 발생 하 는 상황 중 하 나 는 바로 이렇다. 더욱 상세 한 컴 파 일 러 명령 스케줄 링 으로 인 한 문제 에 대해 서 는 이 페이지 [4] 를 참조 할 수 있다.
[3] 에서 컴 파일 러 명령 스케줄 링 의 증 거 를 제공 했다.
instance = new Singleton(); 이 명령 은 Symantec JIT 에서 컴 파일 되 었 습 니 다.
0206106A mov eax,0F97E78h
0206106F call 01F6B210 ; 분배 공간
02061074 mov dword ptr [ebp],eax ; EBP 에 인 스 턴 스 주소 가 저장 되 어 있 습 니 다.
02061077 mov ecx,dword ptr [eax] ; 인용 을 풀 고 새로운 포인터 주 소 를 얻 습 니 다.
02061079 mov dword ptr [ecx],100h ; 다음 네 줄 은 inline 후의 구조 기 입 니 다.
0206107F mov dword ptr [ecx+4],200h
02061086 mov dword ptr [ecx+8],400h
0206108D mov dword ptr [ecx+0Ch],0F84030h
초기 화 전에 할당 이 완료 되 었 고 JLS 가 허용 한 것 을 볼 수 있 습 니 다.
또 다른 상황 은 스 레 드 가 싱글 톤 대상 의 초기 화 를 안정 적 으로 완료 했다 고 가정 하고 동기 화 블록 을 종료 하고 로 컬 메모리 와 메 인 저장 소 를 동기 화 하 는 것 이다.스 레 드 2 가 왔 습 니 다. 비어 있 지 않 은 인용 을 보고 가 져 갑 니 다.스 레 드 2 는 다음 동기 화 블록 에 들 어가 지 않 았 기 때문에 read Barrier 를 실행 하지 않 았 습 니 다.그래서 이때 보 이 는 데이터 가 낡 았 을 가능성 이 높다.
또 많은 사람들 이 이미 알 고 있 는 몇 가지 에 따라 하나의 fix 방법 을 제 시 했 지만 결국 더 많은 문제 가 발생 했다.[3] 중의 소 개 를 참고 할 수 있다.
[5] 인 스 턴 스 필드 를 volatile 로 밝 혀 도 오 류 를 피 할 수 없 는 이 유 를 설명 했다.
이 를 통 해 알 수 있 듯 이 안전 한 Singleton 의 구 조 는 보통 두 가지 방법 밖 에 없다. 하 나 는 클래스 를 불 러 올 때 이 인 스 턴 스 를 만 드 는 것 이 고, 다른 하 나 는 성능 이 떨 어 지 는 synchronized 방법 을 사용 하 는 것 이다.
참고 자료:
[1] Java Language Specification, Second Edition, 제1 7 장 은 자바 의 스 레 드 와 메모리 의 상호작용 관계 에 대한 구체 적 인 세부 사항 을 소개 했다.
[2] out - of - order 와 cache 의 소 개 는 Computer System, A Programmer 's Perspective 의 제4, 5 장 을 참조 할 수 있다.
[3] The "Double-Checked Locking is Broken" Declaration, http://www.cs.umd.edu/~pugh/java/memoryModel/DoubleCheckedLocking.html
[4] Synchronization and the Java Memory Model, http://gee.cs.oswego.edu/dl/cpj/jmm.html
[5] Double-checked locking: Clever, but broken, http://www.javaworld.com/javaworld/jw-02-2001/jw-0209-double.html?page=1
[6] Holub on Patterns, Learning Design Patterns by Looking at Code
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
디자인 모델 의 공장 모델, 단일 모델자바 는 23 가지 디자인 모델 (프로 그래 밍 사상/프로 그래 밍 방식) 이 있 습 니 다. 공장 모드 하나의 공장 류 를 만들어 같은 인 터 페 이 스 를 실현 한 일부 종 류 를 인 스 턴 스 로 만 드 는 것...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.