In a lot of of the Java source, (for example LinkedBlockingDeque
) I see things like this;
final ReentrantLock lock = new ReentrantLock();
publi
Whilst it shouldn't make any difference, it has been stated on mailing lists that there have been slight measured performance difference on actual JREs.
General advice would still be not to bother with the local. It's only there because performance is really, really crucial in specific code used by a lot of people.
Digging in the code a little bit I have found examples for both ways by the same author, Doug Lea:
LinkedBlockingDeque
(since JDK 1.6) uses the "direct access" method.CopyOnWriteArrayList
(since JDK 1.5) uses the "local variable" method.There are more examples for each idiom in java.util.concurrent
but it seems, that for each class a consistent style has been chosen.
Please note, that in all relevant cases the lock
field has been declared final
. That is the most important part, because the memory model semantics for final fields are a bit special in JVM (see JLS).
Building on that: Taking a local copy or not does not affect multithreading correctness.
Also note that Dough Lea has chosen the shorter style in newer code (as shown in the examples). So perhaps the "take a local copy" idiom is some leftover from the days before java.util.concurrent
has been part of the JDK and before the JVM memory model has been adopted appropriately. I speculate that the code before that adoption might have looked like this:
public void op(){
ReentrantLock lock = getLock();
lock.lock();
try {
realOp();
} finally {
lock.unlock();
}
}
where getLock()
did contain some crude multithreading safe logic.
When you assign to local variable in method, compiler can do some optimizations. see In ArrayBlockingQueue, why copy final member field into local final variable?
In this piece of code it doesn't matter: both examples work exactly the same. However if the instance variable lock was not final then it could make a difference as the instance variable could be changed during the locked operation: you then want to make sure that you unlock the same lock that you initially locked.
But as lock is final, it doesn't matter: the local variable assignment in your first example is superfluous.
Hotspot doesn't optimize instance final fields.
In most cases it doesn't matter really, since if the code is compiled and it hits the cache the optimization worth probably 1% however if the code spans though some more code, esp. virtual calls the local load can help predict branching.
I, myself, do the local variable dirty code most of the time if I know/expect it's hot code.
Some further info, incl. Doug Lea personal take on the matter.