면접 문제: 스 레 드 안전 한 단일 모드

면접 에서 스 레 드 가 안전 한 단일 모델 문 제 를 물 었 습 니 다. 제 가 보통 사용 하 는 이런 기법 으로 단일 사례 를 실현 하려 고 합 니 다.
 
public class Singleton {
	
	private Singleton() {}
	private static Singleton instance = null;

	public static Singleton getInstance() {
		if(instance == null) {
			instance = new Singleton();
		}
		return instance;
	}
}

 
단일 사례 의 목적 은 실 행 될 때 Singleton 류 가 유일한 인 스 턴 스 만 있 도록 하 는 것 입 니 다. 가장 많이 사용 되 는 곳 은 데이터 베 이 스 를 연결 하 는 것 입 니 다. Spring 에서 BeanFactory 를 만 드 는 것 입 니 다. 이런 조작 들 은 모두 그들의 방법 으로 특정한 동작 을 수행 하 는 것 입 니 다.
면접 관 의 문 제 는 정례 적 으로 어떤 문 제 를 가 져 올 까?
제 첫 번 째 반응 은 만약 에 여러 개의 스 레 드 가 이 인 스 턴 스 를 동시에 호출 하면 스 레 드 안전 문제 가 있 을 것 입 니 다. 그 때 이렇게 말 했 습 니 다. 그리고 그 는 "어떻게 스 레 드 안전 한 단일 모델 을 실현 합 니까?" 라 고 물 었 습 니 다.
이 질문 에 나 는 대답 하지 않 았 다. 그때 머 릿 속 에 synchronized 로 잠 그 면 질문 이 있 을 수 있 고 어떤 질문 인지 알 고 싶 지 않 으 면 대답 하지 않 는 것 을 선택 했다.
여기 고수 여러분,
1. 수정 대상 의 작업 을 수행 하지 않 으 면 읽 기 작업 만 수행 하고 동기 화 할 필요 가 있 습 니까?
2. 단일 스 레 드 의 안전 한 사용 을 보장 하 는 synchronized 는 어떤 문제 가 발생 합 니까?
3. synchronized 를 사용 하지 않 고 스 레 드 안전 을 보장 하 는 방법 이 있 습 니까?
4. 다음 면접 에서 이런 상황 이 발생 하면 어떤 방식 으로 대답 하면 면접 관 이 만족 할 까요?
 
 
--------------------------------------------------------------------------------------------------------------------------------------------------------------
 
여러분 의 토론 과 지지 에 감 사 드 립 니 다. 정리 해 보 세 요.
 
실제로 어떤 단일 사례 를 사용 하 느 냐 는 서로 다른 생산 환경 에 달 려 있다. 게으름뱅이 식, 즉 내 가 위 에서 들 었 던 예 이다. 이런 방식 은 단일 스 레 드 프로그램 에 적합 하고 다 중 스 레 드 상황 에서 getInstance () 방법 을 보호 해 야 한다. 그렇지 않 으 면 여러 개의 Singleton 대상 의 인 스 턴 스 가 생 길 수 있다.
 
이 를 바탕 으로 getInstance () 방법 을 한 번 에 하나의 스 레 드 로 만 호출 할 수 있 도록 확보 하려 면 getInstance () 방법 전에 추가 해 야 합 니 다. synchronized 키워드, 전체 방법 잠 금,
 
public class Singleton{ 
	private static Singleton instance=null; 
	private Singleton(){} 
	public static synchronized Singleton getInstance(){ 
		if(instance==null){ 
			instance=new Singleton(); 
		} 
		return instance; 
	} 
} 
 
 
그러나 많은 경우 에 우 리 는 전체 방법 을 잠 그 는 것 이 자원 을 소모 하 는 것 이 라 고 생각 합 니 다. 코드 에서 실제 다 중 스 레 드 접근 문제 가 발생 하 는 것 은 인 스 턴 스 = new Singleton () 뿐 입 니 다.이 한 마디,
synchronized 블록 성능 의 영향 을 낮 추기 위해 instance = new Singleton () 만 잠 금 합 니 다.이 'weishuang' 댓 글 에 사 용 된 것 은 바로 이런 방식 이다.
 
 
public class Singleton{ 
	private static Singleton instance=null; 
	private Singleton(){} 
	public static Singleton getInstance(){ 
		if(instance==null){ 
			synchronized(Singleton.class){ 
				instance=new Singleton(); 
			} 
		} 
		return instance; 
	} 
} 
 
 
이러한 실현 방식 을 분석 하면 두 스 레 드 는 인 스 턴 스 가 비어 있 는 지 아 닌 지 를 동시에 판단 하 는 if 구문 내부 에 들 어 갈 수 있 습 니 다. 첫 번 째 스 레 드 는 new 작업 을 수행 하고 두 번 째 스 레 드 가 차단 되 며 첫 번 째 스 레 드 가 실 행 된 후에 두 번 째 스 레 드 는 판단 하지 않 고 new 작업 을 직접 할 수 있 기 때문에 이렇게 하 는 것 도 안전 하지 않 습 니 다.
 
두 번 째 synchronized 블록 에 들 어가 비 공 판단 을 하지 않 은 상황 이 발생 하지 않도록 두 번 째 조건 판단 을 추가 합 니 다. 마치 'tomorrow 009' 가 게시 물 에 답 한 예제 와 같 습 니 다.
 
public static Singleton getInstance(){   
    if(instance == null){   
        synchronize{   
           if(instance == null){   
              instance =  new Singleton();    
           }   
        }   
    }   
    return instance;
}  

 
 
이렇게 해서 2 차 검사 가 발생 했 지만 2 차 검사 자체 에 비교적 은밀 한 문제 가 존재 할 수 있 습 니 다. Peter Haggar Developer Works 에 실 린 글 을 찾 아 보 았 는데 2 차 검사 에 대한 설명 이 매우 상세 합 니 다.
"이중 검사 잠 금 뒤의 이론 은 완벽 합 니 다. 불행 하 게 도 현실 은 완전히 다 릅 니 다. 이중 검사 잠 금 문 제 는 단일 프로세서 나 다 중 프로세서 컴퓨터 에서 순조롭게 실 행 될 것 이 라 고 장담 할 수 없습니다. 이중 검사 잠 금 실패 문 제 는 JVM 의 구현 bug 때 문 이 아니 라 자바 플랫폼 메모리 모델 때 문 입 니 다. 메모리 모델 은 이른바"무질서 쓰기" 도 이러한 관용어 가 실패 한 주요 원인 이다.
 
사실 이 글 을 찾 은 후에 제 문 제 는 대체적으로 해결 할 수 있 었 지만 댓 글 을 본 친구 들 도 저 와 같은 문제 가 있어 서 이 문 제 를 계속 정리 하고 싶 었 습 니 다.
 
2 차 검 사 를 사용 하 는 방법 도 완전히 안전 한 것 은 아니다. 자바 플랫폼 메모리 모델 에서 이른바 '무질서 기록' 을 허용 하면 2 차 검사 에 실패 할 수 있 기 때문에 2 차 검 사 를 사용 하 는 생각 도 통 하지 않 는 다.
 
Peter Haggar 마지막 으로 이런 관점 을 제시 했다. "어떤 형식 으로 든 이중 검사 잠 금 을 사용 해 서 는 안 됩 니 다. 왜냐하면 당신 은 그것 이 어떠한 JVM 실현 에 있어 서도 순조롭게 실 행 될 것 이 라 고 보장 할 수 없 기 때 문 입 니 다."
 
'netrice' 는 답장 에서 '자바 5 이후 의 volatile 키워드' 를 사용 하여 volatile 키워드 로 변 수 를 설명 하고 volatile 로 설명 하 는 변 수 는 순서 가 일치 하 는 것 으로 여 겨 집 니 다. 즉, 다시 정렬 하 는 것 이 아 닙 니 다.그러나 volatile 키워드 의 특성 은 이 게시 물이 논의 한 문제 의 관건 에 적용 되 지 않 는 다.
 
위의 분석 을 통 해 알 수 있 듯 이 게으름뱅이 식 lazy 방식 으로 단일 커 브 를 너무 많이 실현 하고 단일 스 레 드 프로 그래 밍 상황 에서 게으름뱅이 식 단일 사례 를 실현 하 는 것 은 문제 가 없다. 만약 에 다 중 스 레 드 상황 에서 우 리 는 비교적 조심해 야 한다. getInstances () 방법 에 synchronized 키 워드 를 추가 하면 성능 상의 희생 이 있 을 수 있 지만하지만 더 안전 합 니 다.이렇게 큰 모퉁이 를 돌 고 다시 돌 아 왔 다.
 
/*       1 */
public class Singleton{ 
	private static Singleton instance=null; 
	private Singleton(){} 
	public static synchronized Singleton getInstance(){ 
		if(instance==null){ 
			instance=new Singleton(); 
		} 
		return instance; 
	} 
} 
  
Peter Haggar 에서 언급 한 또 다른 실현 방식 은 이 렇 습 니 다. synchronized 키 워드 를 사용 하 는 것 을 포기 하고 static 키 워드 를 사용 합 니 다.
 
/*       2 */
public class Singleton {

  private static Singleton instance = new Singleton();

  private Singleton() {}

  public static Singleton getInstance() {
    return instance;
  }

}

 
이 방식 은 동기 화 를 사용 하지 않 았 으 며, static getInstance () 방법 을 호출 할 때 만 Singleton 의 인용 을 만 들 수 있 도록 확보 하 였 습 니 다.
 
그리고 'keshin' 이 언급 한 방식 은 더욱 민첩 하고 동기 화 를 사용 하지 않 았 으 나 하나의 인 스 턴 스 만 있 음 을 보증 하 며 Lazy 의 특성 도 동시에 가지 게 되 었 다 Lazy Loading Singletons.
 
/*       3 */
public class ResourceFactory {   
    private static class ResourceHolder {   
        public static Resource resource = new Resource();   
    }   
  
    public static Resource getResource() {   
        return ResourceFactory.ResourceHolder.resource;   
    }   
  
    static class Resource {   
    }   
}  
  
위의 방식 은 참고 할 만 한 것 입 니 다. 리 소스 팩 토리 에 개인 정적 내부 클래스 리 소스 홀더 가 추가 되 었 습 니 다. 대외 적 으로 제공 하 는 인 터 페 이 스 는 getResource () 방법 입 니 다. 즉, 리 소스 팩 토리. getResource () 일 때 만 리 소스 대상 이 생 성 됩 니 다.
 
이러한 쓰기 의 교묘 한 점 은 리 소스 팩 토리 가 사용 할 때 리 소스 홀더 가 초기 화 되 지만 리 소스 홀더 에 있 는 리 소스 는 만 들 어 지지 않 았 다 는 것 이다.
 
여기 에는 static 키워드 의 용법 이 포함 되 어 있 습 니 다. static 키 워드 를 사용 하여 수식 하 는 변 수 는 처음 사용 할 때 만 초기 화 됩 니 다. 또한 하나의 클래스 에 static 의 구성원 변 수 는 한 부 만 있 습 니 다. 그러면 몇 개의 스 레 드 가 동시에 방문 하 더 라 도 받 은 Resource 대상 이 똑 같 음 을 보장 합 니 다.
굶 주 린 한식 의 실현 방식 은 비용 이 많이 드 는 것 같 지만 라인 안전 에 문제 가 생기 지 않 고 라인 안전 을 해결 하 는 단일 사례 로 실현 하 는 효과 적 인 방식 이다.
 
ThreadLocal 에 대해 서 는 장면 을 사용 해서 결정 해 야 한다 고 생각 합 니 다.
 
에서 작 가 는 다음 과 같이 말 했다."굶 주 린 한식 단 례 류 는 자바 언어 로 가능 하지만, C + + 에서 쉽게 구현 되 지 않 습 니 다. 정적 초기 화 는 C + + 에 고정된 순서 가 없 기 때문에 정적 인 instance 변수의 초기 화 와 클래스 의 로 딩 순서 가 보장 되 지 않 아 문제 가 생 길 수 있 습 니 다. 이것 이 바로 GoF 가 단 례 류 의 개념 을 제시 할 때 예 를 들 면 게 으 른 식 입 니 다. 그들의 책 은 자바 의 영향 을 많이 받 아 자바 에 영향 을 주 었 습 니 다."언어 에서 단 례 류 의 예 도 대부분 게으름뱅이 식 이다. 실제로 이 책 은 굶 주 린 한식 단 례 류 가 자바 언어 자체 의 특징 에 더욱 부합된다 고 생각한다."
 
이 를 통 해 알 수 있 듯 이 디자인 모델 을 응용 하 는 동시에 구체 적 인 사용 장면 을 분석 하여 적당 한 실현 방식 을 선택 하 는 것 이 필요 하 다.
 
문제 해결 과정 에서 찾 은 참고 자 료 를 찾 습 니 다.
오래된 스티커 테마 잠 금: [전환] 단일 사례 모델 완전 분석
잠 금 및 단일 모드 이중 검사
Lazy Loading Singletons
 
에센스 에서 이 문 제 를 유창 하 게 설명 하 는 내용 을 찾 지 못 해 이 글 을 올 렸 지만 불행 하 게 도 초보 자로 평 가 받 았 습 니 다. 하지만 다음 에 면접 관 이 스 레 드 안전 에 관 한 단일 모델 질문 을 하면 어떻게 대답 해 야 할 지 알 것 같 습 니 다.
 
 
 
 
 
 

좋은 웹페이지 즐겨찾기