Почему он не использует поле экземпляра напрямую, но назначает его локальной переменной?
Я читаю источник java.util.concurrent.ArrayBlockingQueue
, и нашел код, который я не понимаю:
private final ReentrantLock 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();
}
}
Обратите внимание на эту строку:
final ReentrantLock lock = this.lock;
Почему он не использует this.lock
напрямую, но назначает его локальной переменной?
Ответы
Ответ 1
Возможно ли это для оптимизации?
Возможно, локальная переменная может быть легко передана в регистр с помощью JIT-компилятора.
По крайней мере, в Android для первых версий API доступ к локальной переменной был дешевле, чем доступ к переменной экземпляра (нельзя говорить для более новых версий). Может быть, простая Java одна и та же, и в некоторых случаях имеет смысл использовать локальную.
Собственно, нашел поток, подтверждающий это здесь. Выдержка:
Это стиль кодирования, популярный Дугом Ли. Это крайность оптимизация, которая, вероятно, не нужна; вы можете ожидать, что JIT сделать ту же оптимизацию. (вы можете попробовать проверить машинный код себя!) Тем не менее, копирование на локальных жителей производит наименьшее байт-код, а для низкоуровневого кода приятно писать код, который немного ближе к машине.
Ответ 2
Так как он просто копирует ссылку и блокировка находится на объекте, а объект тот же, это не имеет значения.
Блокировка переменной экземпляра также объявлена окончательной, так что, действительно, я не вижу смысла делать копию ссылки.
Как отметил JRL, это оптимизация, но на самом деле такая крошечная микро-оптимизация, что я до сих пор не вижу смысла делать это, особенно для всего одного чтения.
Ответ 3
Лучше безопасно, чем сожалеть?
Я предполагаю, что при написании фундаментальных библиотек вам лучше пойти на самое безопасное решение, если оно будет достаточно дешевым. И это очень дешево.
-
Что касается производительности, локальная переменная должна быть быстрее, чем доступ к полям. Я думаю, что любое JVM, заслуживающее своего имени, будет делать такую тривиальную оптимизацию (*), но как насчет интерпретируемого кода и, возможно, C1 (первого, быстрого и низкокачественного компилятора в Oracle JVM)? Это не будет иметь большого значения, но сохраненные микросекунды рассчитаны на миллионы пользователей. Что касается Java, работающего на экзотических платформах с JVM еще не написанным...
-
final
в действительности не является окончательным. Поле может быть изменено с помощью отражения. Я не могу представить никаких причин для этого, и каждый, кто делает такие забавные вещи, получает то, что заслуживает. OTOH отлаживает такие проблемы, может занять много дней, и надежное программирование - хорошая привычка при написании такого фундаментального материала.
(*) Я считаю, что прочитал статью кого-то авторитетного, утверждающего обратное, но я не могу найти его сейчас.