Programing

JDK 소스 코드가 '휘발성'인스턴스의 '최종'복사본을 사용하는 이유

lottogame 2020. 10. 22. 07:35
반응형

JDK 소스 코드가 '휘발성'인스턴스의 '최종'복사본을 사용하는 이유


ConcurrentHashMap에 대한 JDK의 소스 코드를 읽었습니다.

그러나 다음 코드는 나를 혼란스럽게 만들었습니다.

public boolean isEmpty() {
    final Segment<K,V>[] segments = this.segments;
    ...
}

내 질문은 :

"this.segments"는 다음과 같이 선언됩니다.

final Segment<K,V>[] segments;

따라서 여기에서 메서드의 시작 부분에서 동일한 유형 참조를 선언하고 동일한 메모리를 가리 킵니다.

저자는 왜 이렇게 썼습니까? 왜 그들은 this.segments를 직접 사용하지 않았습니까? 이유가 있나요?


이것은 volatile변수를 포함하는 잠금없는 코드의 전형적인 관용구 입니다. 첫 번째 줄에서 volatile한 번 읽은 다음 작업합니다. 그 동안 다른 스레드가을 업데이트 할 수 volatile있지만 처음에 읽은 값에만 관심이 있습니다.

또한 문제의 멤버 변수가 휘발성이 아니라 최종적인 경우에도 스택 위치에서 읽는 것이 임의의 힙 위치에서 읽는 것보다 캐시 친화적이므로이 관용구는 CPU 캐시와 관련이 있습니다. 또한 로컬 변수가 CPU 레지스터에 바인딩 될 가능성이 더 높습니다.

후자의 경우 JIT 컴파일러가 일반적으로 이러한 문제를 처리하기 때문에 실제로 논란이 있지만 Doug Lea는 일반적인 원칙을 고수하는 사람 중 하나입니다.


성능을 고려한 것이므로 필드 값을 한 번만 검색하면됩니다.

Joshua Bloch의 효과적인 자바에서 단일 관용구를 참조 할 수 있습니다.

그의 싱글 톤은 다음과 같습니다.

private volatile FieldType field;
FieldType getField() {
  FieldType result = field;
  if (result == null) { 
    synchronized(this) {
      result = field;
      if (result == null) 
        field = result = computeFieldValue();
    }
  }
  return result;
}

그리고 그는 다음과 같이 썼습니다.

이 코드는 약간 복잡하게 보일 수 있습니다. 특히 지역 변수 결과에 대한 필요성이 명확하지 않을 수 있습니다. 이 변수가하는 일은 필드가 이미 초기화 된 일반적인 경우에 한 번만 읽히도록하는 것입니다. 꼭 필요한 것은 아니지만 이는 성능을 향상시킬 수 있으며 낮은 수준의 동시 프로그래밍에 적용되는 표준에 의해 더욱 우아합니다. 내 컴퓨터에서 위의 방법은 로컬 변수가없는 명백한 버전보다 약 25 % 빠릅니다 .


바이트 코드 크기를 줄일 수 있습니다. 로컬 변수에 액세스하는 것이 인스턴스 변수에 액세스하는 것보다 바이트 코드가 더 짧습니다.

런타임 최적화 오버 헤드도 줄일 수 있습니다.

그러나 이들 중 어느 것도 중요하지 않습니다. 코드 스타일에 관한 것입니다. 인스턴스 변수에 익숙하다면 꼭. Doug Lea는 아마도 지역 변수를 다루는 것이 더 편할 것입니다 .

참고 URL : https://stackoverflow.com/questions/13155860/why-does-jdk-sourcecode-take-a-final-copy-of-volatile-instances

반응형