W ArrayBlockingQueue, po co kopiować końcowe pole składowe do lokalnej zmiennej końcowej?

81

W programie ArrayBlockingQueuewszystkie metody, które wymagają blokady, kopiują ją do finalzmiennej lokalnej przed wywołaniem 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();
    }
}

Czy jest jakiś powód, aby skopiować this.lockdo zmiennej lokalnej, lockgdy pole this.lockjest final?

Dodatkowo używa również lokalnej kopii E[]przed podjęciem działań na niej:

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

Czy jest jakiś powód do kopiowania końcowego pola do lokalnej zmiennej końcowej?

mjlee
źródło

Odpowiedzi:

68

To ekstremalna optymalizacja, której lubi używać Doug Lea, autor klasy. Oto post w ostatnim wątku na liście mailingowej core-libs-dev na ten dokładnie temat, który całkiem dobrze odpowiada na twoje pytanie.

z postu:

... kopiowanie do lokalnych generuje najmniejszy kod bajtowy, a dla kodu niskiego poziomu dobrze jest napisać kod, który jest trochę bliżej maszyny

ColinD
źródło
15
Duży nacisk na „ekstremalne”! Nie jest to dobra praktyka programistyczna ogólnego przeznaczenia, którą każdy powinien naśladować.
Kevin Bourrillion
15
Losowa informacja do Twojej wiadomości: w niektórych innych przypadkach, gdy widzisz, że jest to zrobione, dzieje się tak, ponieważ dane pole jest niestabilne, a metoda musi mieć pewność, że ma dla niego jedną spójną wartość lub odniesienie.
Kevin Bourrillion
2
Przyjmę tę „ekstremalną” optymalizację w podstawowej klasie, takiej jak ta.
Erick Robertson
4
@zamza, lokalne zmienne końcowe są używane tylko przez kompilator java, a nie przez kod bajtowy (tj. JVM nie wie, czy zmienna lokalna jest ostateczna)
bestsss
1
Czy oprócz rozmiaru kodu bajtowego jest to również optymalizacja pod kątem szybkości wykonywania?
SantiBailors
13

Ten wątek zawiera kilka odpowiedzi. W istocie:

  • kompilator nie może łatwo udowodnić, że końcowe pole nie zmienia się w ramach metody (z powodu odbicia / serializacji itp.)
  • większość obecnych kompilatorów właściwie nie próbuje i dlatego musiałaby przeładowywać ostatnie pole za każdym razem, gdy jest używane, co może prowadzić do braku pamięci podręcznej lub błędu strony
  • zapisanie go w zmiennej lokalnej zmusza maszynę JVM do wykonania tylko jednego ładowania
asylias
źródło
2
Nie sądzę, aby finalzmienna musiała być ponownie ładowana przez JVM. Jeśli zmodyfikujesz finalzmienną przez odbicie, stracisz gwarancję, że Twój program będzie działał poprawnie (co oznacza, że ​​nowa wartość może nie zostać uwzględniona we wszystkich przypadkach).
icza