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?

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


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

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
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.