Чому в 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в локальну змінну, lockколи поле this.lockє final?

Крім того, він також використовує локальну копію 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

Це надзвичайна оптимізація, яку любить використовувати Дуг Лі, автор класу. Ось допис про недавню тему в списку розсилки core-libs-dev про цю точну тему, яка досить добре відповідає на ваше запитання.

з поста:

... копіювання до місцевих жителів дає найменший байт-код, а для коду низького рівня приємно писати код, який трохи ближче до машини


15
Сильний наголос на "екстримі"! Це не є загальноприйнятою доброю практикою програмування, на яку повинні наслідувати всі.
Кевін Бурріллон,

15
Випадковий FYI: у деяких інших випадках, коли ви бачите, що це зроблено, це тому, що поле, про яке йде мова, є мінливим, і метод повинен переконатися, що він має єдине узгоджене значення або посилання для нього на всьому протязі.
Kevin Bourrillion

2
Я прийму цю "екстремальну" оптимізацію в такому базовому класі.
Ерік Робертсон,

4
@zamza, локальні кінцеві змінні використовуються лише компілятором Java, а не байт-кодом (тобто JVM не знає, чи є локальна змінна остаточною)
bestsss

1
На додаток до розміру байт-коду, це оптимізація також для швидкості виконання?
SantiBailors

13

Ця тема дає деякі відповіді. По суті:

  • компілятор не може легко довести, що останнє поле не змінюється в межах методу (через відображення / серіалізацію тощо)
  • більшість сучасних компіляторів насправді не намагаються, і тому їм доведеться перезавантажувати останнє поле кожного разу, коли воно використовується, що може призвести до пропуску кешу або помилки сторінки
  • зберігання його в локальній змінній змушує JVM виконувати лише одне навантаження

2
Я не думаю, що finalзмінна повинна перезавантажуватися JVM. Якщо ви зміните finalзмінну за допомогою відображення, ви втратите гарантію правильної роботи програми (тобто нове значення може враховуватися не у всіх випадках).
icza
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.