ArrayBlockingQueue에서 최종 멤버 필드를 로컬 최종 변수에 복사하는 이유는 무엇입니까?


81

에서 ArrayBlockingQueue, 잠금을 필요로하는 모든 방법은 로컬에 복사 final호출하기 전에 변수 lock().

public boolean offer(E e) {
    if (e == null) throw new NullPointerException();
    final ReentrantLock lock = this.lock;
    lock.lock();
    try {
        if (count == items.length)
            return false;
        else {
            insert(e);
            return true;
        }
    } finally {
        lock.unlock();
    }
}

필드 가 있을 때 this.lock지역 변수 에 복사 할 이유 가 있습니까?lockthis.lockfinal

또한 작업 E[]하기 전에 의 로컬 사본도 사용 합니다.

private E extract() {
    final E[] items = this.items;
    E x = items[takeIndex];
    items[takeIndex] = null;
    takeIndex = inc(takeIndex);
    --count;
    notFull.signal();
    return x;
}

최종 필드를 지역 최종 변수에 복사하는 이유가 있습니까?

답변:


68

클래스의 저자 인 Doug Lea가 사용하기를 좋아하는 극단적 인 최적화입니다. 다음 은 core-libs-dev 메일 링 목록 의 최근 스레드 에 대한 게시물 이 정확한 주제에 대해 귀하의 질문에 꽤 잘 대답합니다.

게시물에서 :

... 로컬로 복사하면 가장 작은 바이트 코드가 생성되며, 저수준 코드의 경우 기계에 조금 더 가까운 코드를 작성하는 것이 좋습니다.


15
"극단적"에 대한 강한 강조! 이것은 모든 사람이 에뮬레이트해야하는 범용 좋은 프로그래밍 관행이 아닙니다.
Kevin Bourrillion

15
Random FYI : 다른 경우에이 작업이 완료되면 해당 필드가 휘발성이기 때문이며 메서드는 전체에 대해 일관된 단일 값 또는 참조가 있는지 확인해야합니다.
Kevin Bourrillion

2
나는 이와 같은 핵심 클래스에서이 "극단적 인"최적화를 취할 것입니다.
Erick Robertson

4
@zamza, 로컬 최종 변수는 바이트 코드가 아닌 자바 컴파일러에서만 사용됩니다 (즉, JVM은 로컬 변수가 최종인지 알 수 없음)
bestsss

1
바이트 코드 크기 외에도 실행 속도 최적화입니까?
SantiBailors

13

이 스레드 는 몇 가지 답변을 제공합니다. 실질적으로 :

  • 컴파일러는 메서드 내에서 최종 필드가 변경되지 않는다는 것을 쉽게 증명할 수 없습니다 (반사 / 직렬화 등으로 인해)
  • 대부분의 최신 컴파일러는 실제로 시도하지 않으므로 캐시 미스 또는 페이지 오류로 이어질 수있는 최종 필드를 사용할 때마다 다시로드해야합니다.
  • 로컬 변수에 저장하면 JVM이 하나의로드 만 수행합니다.

2
finalJVM 에서 변수를 다시로드 해야한다고 생각하지 않습니다 . final리플렉션을 통해 변수를 수정하면 프로그램이 올바르게 작동하지 않을 수 있습니다 (즉, 모든 경우에 새 값이 고려되지 않을 수 있음).
icza
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.