Java Concurrent Programming (7)

더 읽 기
7. Double-Checked Locking
  이중 검사 잠 금 메커니즘 은 상투적인 문제 이다.이중 검사 잠 금 체 제 는 이미 광범 위 하 게 인용 되 었 으 며, 특히 다 중 스 레 드 환경 에서 의 게 으 른 로드 실현 에 있어 서 는.그러나 추가 동기 화가 없 으 면 자바 플랫폼 에서 독립 적 으로 실행 할 수 없습니다.이 코드 를 보십시오.

public class Singleton {
	
	private Singleton instance = null;
	
	public Singleton getInstance(){
		if(instance == null){
			instance = new Singleton();
		}
		return instance;
	}
	
	// other function
}

  이 코드 가 다 중 스 레 드 환경 에서 실행 되면 많은 오류 가 발생 할 수 있 습 니 다.가장 눈 에 띄 는 것 은 싱글 턴 대상 이 두 번 이나 두 번 이상 예화 된다 는 점 이다.이 오 류 를 해결 하기 위해 서 는 getInstance () 방법 에 synchronized 키 워드 를 추가 하고 고 친 종 류 는 다음 과 같 습 니 다.

public class Singleton {
	
	private Singleton instance = null;
	
	public synchronized Singleton getInstance(){
		if(instance == null){
			instance = new Singleton();
		}
		return instance;
	}
	
	// other function
}

  현재 getInstance () 방법 을 호출 할 때마다 동기 화 됩 니 다.이중 검사 잠 금 메커니즘 은 인 스 턴 스 가 null 이 아 닐 때 추가 동기 화 비용 이 발생 하지 않도록 코드 가 생 겼 습 니 다.

public class Singleton {
	
	private Singleton instance = null;
	
	public Singleton getInstance(){
		if(instance == null){
			synchronized(this){
				if(instance == null){
					instance = new Singleton();
				}
			}
		}
		return instance;
	}
	
	// other function
}

  그러나 이 코드 가 최 적 화 된 컴 파일 러 나 공유 메모리 다 중 프로세서 가 존재 하 는 상황 에서 실행 된다 면 통 하지 않 습 니 다.주로 오래된 자바 메모리 모델 로 인해 getInstance () 방법 을 호출 한 후 비 어 있 는 인 스 턴 스 참조 가 보이 지만, singleton 의 모든 속성 은 구조 함수 에서 지정 한 값 이 아 닌 기본 값 입 니 다.컴 파일 러 가 구조 함수 가 이상 을 던 지지 않 거나 동기 화 를 실행 하지 않도록 보장 할 수 있다 면 컴 파일 러 내 연 된 구조 함수 가 호출 되 었 다 면 인 스 턴 스 와 모든 속성 을 초기 화 하 는 쓰기 작업 은 재 순 될 것 입 니 다.컴 파일 러 가 정렬 을 다시 하지 않 더 라 도 다 중 핵 처리 나 메모리 시스템 에서 정렬 을 다시 할 수 있 습 니 다.그래서 다음 과 같은 개선 이 있 었 다.

public class Singleton {
	
	private Singleton instance = null;
	
	public Singleton getInstance(){
		if(instance == null){
			Singleton s ;
			synchronized(this){
				s = instance;
				if(s == null){
					synchronized(this){
						s = new Singleton();
					} // release inner synchronization lock
				}
				instance = s;
			}
		}
		return instance;
	}
}

인용 하 다.
This code puts construction of the Singleton object inside an inner synchronized block. The intuitive idea here is that there should be a memory barrier at the point where synchronization is released, and that should prevent the reordering of the initialization of the Helper object and the assignment to the field helper.
Unfortunately, that intuition is absolutely wrong. The rules for synchronization don't work that way. The rule for a monitorexit (i.e., releasing synchronization) is that actions before the monitorexit must be performed before the monitor is released. However, there is no rule which says that actions after the monitorexit may not be done before the monitor is released. It is perfectly reasonable and legal for the compiler to move the assignment instance = s; inside the synchronized block, in which case we are back where we were previously. Many processors offer instructions that perform this kind of one-way memory barrier. Changing the semantics to require releasing a lock to be a full memory barrier would have performance penalties.
  Alexander Terekhov 는 매우 교묘 한 문제 해결 방법 을 생각해 냈 고 ThreadLocal 변 수 를 통 해 이중 검사 잠 금 메커니즘 문 제 를 실현 했다.

public class Singleton {
	
	/** If perThreadInstance.get() returns a non-null value, this thread
	has done synchronization needed to see initialization
	of helper */
	private final ThreadLocal local = new ThreadLocal();
	
	private Singleton instance = null;
	
	public Singleton getInstance(){
		if(local.get() == null){
			createInstance();
		}
		return instance;
	}
	
	private final void createInstance(){
		 synchronized(this) {
             if (instance == null)
            	 instance = new Singleton();
         }
		 local.set(instance);

	}
	// other function
}

  이 코드 의 성능 은 JDK 의 실현 에 달 려 있다.JDK 1.2 에서 ThreadLocal 은 매우 느 려 서 1.3 이 뚜렷하게 향상 되 었 다.비록 이 코드 는 현재 로 서 는 잘못된 것 같 지만, 당시 에는 이중 검사 자물쇠 메커니즘 으로 인 한 문 제 를 확실히 해결 했다.
  JDK 1.5 이후 새로운 자바 메모리 모델 과 스 레 드 규범 후 volitale 키 워드 를 통 해 읽 기와 쓰기 의 재 순 서 를 방지 하고 이중 검사 잠 금 체제 로 인 한 문 제 를 해결 할 수 있 습 니 다.

public class Singleton {
	
	private volatile Singleton instance = null;
	
	public Singleton getInstance(){
		if(instance == null){
			synchronized(this){
				if(instance == null){
					instance = new Singleton();
				}
			}
		}
		return instance;
	}
	
	// other function
}

  싱글 톤 이 가 변 적 이지 않 은 대상 이 고 모든 속성 이 가 변 적 이지 않다 면 volatile 키 워드 를 수식 할 필요 가 없습니다.자바 언어 는 가 변 적 이지 않 은 대상 에 대한 인용 으로 그 행 위 는 int, float 와 같 기 때문에 읽 기와 쓰기 작업 은 모두 원자 적 이다.
  그러나 가장 간단 하고 고상 한 방식 으로 인 스 턴 스 를 만 드 는 것 은 static 를 사용 하 는 것 입 니 다.

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

  자바 언어 에 따 르 면 필드 의 초기 화 는 인 용 된 후에 이 루어 지 며 모든 스 레 드 는 필드 에서 초기 화 된 후에 해당 하 는 작업 을 할 것 입 니 다.
Reference :
  http://www.cs.umd.edu/~pugh/java/memoryModel/
  http://gee.cs.oswego.edu/dl/cpj/jmm.html

좋은 웹페이지 즐겨찾기