Важно ли копировать ссылку на локальную переменную перед ее использованием

Изучая код java.util.LinkedList, как и в OpenJDK 8, я нашел следующий код. Код прост, но я смущен тем, что сохраняю ссылку на первый node на константу во второй строке кода. Насколько я понимаю, этот код будет привязан к однострочному без копирования ссылок. Я прав? Если это так, , почему нужно копировать ссылку в этой и подобных ситуациях (такая идиома может быть найдена в половине методов в java.util.LinkedList)?

public E peek() {
    final Node<E> f = first;
    return (f == null) ? null : f.item;
}

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

Ответ 1

Моя первая мысль заключалась в том, что она помогает concurrency каким-то образом...

... поэтому я думаю, что это некоторый намек на оптимизатор...

И.:-) Тот факт, что LinkedList не поддерживает concurrency, не означает, что авторы все равно не будут следовать хорошей практике, и он сообщает компилятору и JIT, что они должны искать только first один раз.

Без локальной переменной f у нас будет:

public E peek() {
    return (this.first == null) ? null : this.first.item;
}

Я добавил подразумеваемый this., чтобы подчеркнуть, что first - это поле экземпляра.

Итак, если часть this.first == null оценивается в потоке A, тогда this.first изменяется на Thread B, когда this.first.item оценивается в Thread A, он может бросать, потому что this.first стал null в То время. Это невозможно при f, потому что f является локальным; будет видеть только поток, выполняющий вызов peek.

Часть final является хорошей документацией в коде (поскольку автор никогда не намеревается изменить значение f) и подсказкой к оптимизатору, который мы никогда не будем менять f, что означает что, когда пришло время оптимизировать, он может оптимизировать его на дюйм своей жизни, зная, что ему только нужно читать this.first один раз, а затем использовать значение регистра или стека для обоих проверка null и возврат.