Vladimir Nazarenko Vladimir Nazarenko - 4 months ago 5x
Java Question

Is it important to copy reference before using in Java?

Exploring the code of java.util.LinkedList as it is in OpenJDK 8, I found the following code. The code is straightforward, but I'm confused about saving reference to the first node to a constant in the second line of code. As far as I understand, this code will be inlined to one-liner without reference copying. Am I right? If so, why does one need to copy reference in this and similar situations (such idiom may be found in a half of methods in java.util.LinkedList)?

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

My first thought was that it helps concurrency in some way, but LinkedList does not allow concurrent access (except at your own risk), so I guess it is some hint for optimizer, but can't figure out how it is supposed to work.


My first thought was that it helps concurrency in some way...

...so I guess it is some hint for optimizer...

Both. :-) The fact that LinkedList doesn't support concurrency doesn't mean that the authors aren't going to follow good practices anyway, and it tells the compiler and the JIT that they should only look up first once.

Without the f local variable, we'd have:

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

I've added the implied this. to emphasize that first is an instance field.

So if the this.first == null part is evaluated on Thread A, then this.first is changed on Thread B, when this.first.item is evaluated on Thread A, it may throw because this.first has become null in the meantime. That's impossible with f, because f is local; only the thread running the peek call will see it.

The final part is both good in-code documentation (as the author never intends to change the value of f) and a hint to the optimizer that we're never going to change f, which means that when it comes time to optimize, it can optimize it to within an inch of its life, knowing that it only ever has to read this.first once and can then use a register or stack value for both the null check and the return.