Подтвердить что ты не робот

Почему он не использует поле экземпляра напрямую, но назначает его локальной переменной?

Я читаю источник 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 напрямую, но назначает его локальной переменной?

4b9b3361

Ответ 1

Возможно ли это для оптимизации?

Возможно, локальная переменная может быть легко передана в регистр с помощью JIT-компилятора.

По крайней мере, в Android для первых версий API доступ к локальной переменной был дешевле, чем доступ к переменной экземпляра (нельзя говорить для более новых версий). Может быть, простая Java одна и та же, и в некоторых случаях имеет смысл использовать локальную.

Собственно, нашел поток, подтверждающий это здесь. Выдержка:

Это стиль кодирования, популярный Дугом Ли. Это крайность оптимизация, которая, вероятно, не нужна; вы можете ожидать, что JIT сделать ту же оптимизацию. (вы можете попробовать проверить машинный код себя!) Тем не менее, копирование на локальных жителей производит наименьшее байт-код, а для низкоуровневого кода приятно писать код, который немного ближе к машине.

Ответ 2

Так как он просто копирует ссылку и блокировка находится на объекте, а объект тот же, это не имеет значения.

Блокировка переменной экземпляра также объявлена ​​окончательной, так что, действительно, я не вижу смысла делать копию ссылки.

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

Ответ 3

Лучше безопасно, чем сожалеть?

Я предполагаю, что при написании фундаментальных библиотек вам лучше пойти на самое безопасное решение, если оно будет достаточно дешевым. И это очень дешево.

  • Что касается производительности, локальная переменная должна быть быстрее, чем доступ к полям. Я думаю, что любое JVM, заслуживающее своего имени, будет делать такую ​​тривиальную оптимизацию (*), но как насчет интерпретируемого кода и, возможно, C1 (первого, быстрого и низкокачественного компилятора в Oracle JVM)? Это не будет иметь большого значения, но сохраненные микросекунды рассчитаны на миллионы пользователей. Что касается Java, работающего на экзотических платформах с JVM еще не написанным...

  • final в действительности не является окончательным. Поле может быть изменено с помощью отражения. Я не могу представить никаких причин для этого, и каждый, кто делает такие забавные вещи, получает то, что заслуживает. OTOH отлаживает такие проблемы, может занять много дней, и надежное программирование - хорошая привычка при написании такого фундаментального материала.


(*) Я считаю, что прочитал статью кого-то авторитетного, утверждающего обратное, но я не могу найти его сейчас.