86

In ArrayBlockingQueue, all the methods that require the lock copy it to a local final variable before calling 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();
    }
}

Is there any reason to copy this.lock to a local variable lock when the field this.lock is final?

Additionally, it also uses a local copy of E[] before acting on it:

private E extract() {
    final E[] items = this.items;
    E x = items[takeIndex];
    items[takeIndex] = null;
    takeIndex = inc(takeIndex);
    --count;
    notFull.signal();
    return x;
}

Is there any reason for copying a final field to a local final variable?

Mark Rotteveel
  • 100,966
  • 191
  • 140
  • 197
mjlee
  • 3,374
  • 4
  • 27
  • 22

2 Answers2

71

It's an extreme optimization Doug Lea, the author of the class, likes to use. Here's a post on a recent thread on the core-libs-dev mailing list about this exact subject which answers your question pretty well.

from the post:

...copying to locals produces the smallest bytecode, and for low-level code it's nice to write code that's a little closer to the machine

akf
  • 38,619
  • 8
  • 86
  • 96
ColinD
  • 108,630
  • 30
  • 201
  • 202
  • 16
    Strong emphasis on "extreme"! This is not a general-purpose good programming practice that everyone should be emulating. – Kevin Bourrillion May 07 '10 at 13:42
  • 15
    Random FYI: in some other cases when you see this done, it's because the field in question is volatile, and the method needs to make sure it's got a single consistent value or reference for it throughout. – Kevin Bourrillion May 07 '10 at 13:44
  • 2
    I'll take this "extreme" optimization in a core class like this. – Erick Robertson Jan 13 '11 at 12:58
  • Ok, the copying trick is clear. But why copy to a final local variable? Just to give a hint to one who reads the code, or it gives some hidden bytecode profit as well? – zamza Sep 20 '11 at 13:11
  • @zamza Isn't that what I answered here? It produces smaller bytecode. – ColinD Sep 20 '11 at 14:30
  • I understand that copying to local produces smaller code, but this local variable could have been not final. I wonder if local variable finality makes any difference. I.e. is `final ReentrantLock lock = this.lock;` somehow different from `ReentrantLock lock = this.lock;` – zamza Sep 21 '11 at 14:39
  • 5
    @zamza, local final variables are only used by java compiler, not the bytecode (i.e. JVM doesn't know if a local variable is final) – bestsss Nov 06 '11 at 01:32
  • 1
    In addition to bytecode size, is this an optimization also for execution speed ? – SantiBailors Feb 09 '17 at 09:08
  • 1
    @SantiBailors: AFAIK there's no execution speed benefit, but I don't know for sure. – ColinD Feb 13 '17 at 18:09
13

This thread gives some answers. In substance:

  • the compiler can't easily prove that a final field does not change within a method (due to reflection / serialization etc.)
  • most current compilers actually don't try and would therefore have to reload the final field everytime it is used which could lead to a cache miss or a page fault
  • storing it in a local variable forces the JVM to perform only one load
assylias
  • 321,522
  • 82
  • 660
  • 783
  • 2
    I don't think a `final` variable has to be reloaded by the JVM. If you modify a `final` variable via reflection, you lose guarantee of your program working correctly (meaning the new value might not be taken into account in all cases). – icza Oct 01 '14 at 06:35