2

While browsing through the source code of the java.util.concurrency package, I noticed an idiomatic use of ReentrantLock that I had not seen before: member RentrantLock variables were never accessed directly from within a method - they were always referenced by a local variable reference.

Style #1 e.g from java.util.concurrent.ThreadPoolExecutor

private final ReentrantLock mainLock = new ReentrantLock();
...
// why a local reference to final mainlock instead of directly using it?
final ReentrantLock mainLock = this.mainLock; 
mainLock.lock();
try {
...     
} finally {
  mainLock.unlock();
}

However, in other places the final member variable is used directly, without first obtaining a local reference.

Style #2 e.g. from Java Concurrency in Practice

private final Lock lock = new ReentrantLock();
...
// here the final lock is used directly
lock.lock();   
try {
...
} finally {
lock.unlock();
}

I would like to understand what are the benefits of using Style #1 over Style #2?

Thanks

Update

Thanks for all of responses, especially Ben Manes for first identifying performance. As a result I was able to discover the following additional details

  1. Doug Lea introduced this idiom in 2003 with a comment "cache finals across volatiles"
  2. According to Doug, it is "for performance-critical code like that inside j.u.c." and while "It's not a recommended practice", he "does not discourage it either"
  3. Brian Goetz (author of JCIP) also agrees that unless it is for performance-critical applications "don't worry"
Ulrich Palha
  • 9,411
  • 3
  • 25
  • 31
  • As far as I know there are none. It is a `final` member so there is no point in grabbing a local reference. It may indicate that two different programmers worked on those sections of code -- nothing more. – Gray Nov 11 '11 at 05:10
  • I can't see a reason to take a local variable unless a previous version of the code had `mainLock` being defined as non-final. –  Nov 11 '11 at 05:12
  • 2
    See this [thread](http://old.nabble.com/Making-copy-of-a-reference-to-ReentrantLock-tt30730392.html#a30733348) for details on this trick for byte code optimization. – Ben Manes Nov 11 '11 at 06:09
  • @BenManes Interesting - the discussion there appears to settle on the fact that final is not necessarily final, so the compiler will not necessarily optimise it, which is why the code is written like that - for a minor speed improvement with JIT. –  Nov 11 '11 at 09:22
  • @BenManes I believe performance was the reason. Thanks for that thread – Ulrich Palha Nov 11 '11 at 18:12

1 Answers1

2

Ben Manes linked to a discussion in the comments that talks about JIT optimisation. Apparently the hotspot compiler will not optimise the loads of a final field because it can be modified via reflection or with the Unsafe class.

Therefore this mechanism gives a minor speed improvement allowing JIT to optimise loads of the lock instance. They didn't go into detail of which optimisation would occur, but I suspect the optimisation is for preventing reloading the instance from main memory. This would allow a Thread to use the Re-entrant lock multiple times without penalty.

Unfortunately this answer is speculation based upon a mailing list discussion. If someone can correct me please go ahead!

  • Yep, see this [blog post](http://www.azulsystems.com/blog/cliff/2011-10-27-final-fields-part-2) for more insights. – Ben Manes Nov 12 '11 at 22:15