2010-05-07 3 views
64

В ArrayBlockingQueue все методы, требующие блокировки, копируют его в локальную переменную final перед вызовом lock().В ArrayBlockingQueue, зачем копировать конечное поле участника в локальную конечную переменную?

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; 
} 

Есть ли основания для копирования окончательного поля к локальной окончательной переменной?

ответ

52

Это экстремальная оптимизация Doug Lea, автор класса, любит использовать. Вот сообщение на a recent thread в списке рассылки core-libs-dev об этом точном вопросе, который хорошо отвечает на ваш вопрос.

от должности:

... копирование местных жителей производит наименьшее байткод, а для кода низкоуровневой приятно писать код , это немного ближе к машине

+11

Сильного акцент на «экстремальный»! Это не универсальная хорошая практика программирования, которую каждый должен подражать. –

+12

Случайный FYI: в некоторых других случаях, когда вы видите это, это потому, что поле, о котором идет речь, является изменчивым, и метод должен убедиться, что он имеет одно постоянное значение или ссылку для него во всем. –

+2

Я возьму эту «экстремальную» оптимизацию в таком базовом классе. –

9

This thread дает некоторые ответы. По существу:

  • компилятор не может легко доказать, что окончательное поле не изменяется в пределах метода (за счет отражения/сериализации и т.д.)
  • большинство нынешних составителей фактически не пытаются и, следовательно, будет иметь перезагрузить конечное каждый раз поля он используется, что может привести к промаху кэша или сбою страницы
  • хранящего его в локальном переменном заставляет JVM выполнять только одну загрузки
+1

Я не думаю, что переменная 'final' должна быть перезагружена JVM. Если вы изменяете переменную 'final' посредством отражения, вы теряете гарантию своей работы (что означает, что новое значение может не учитываться во всех случаях). – icza