在ArrayBlockingQueue中,为什么要将最终成员字段复制到本地最终variables?
在ArrayBlockingQueue
,所有需要锁的方法在调用lock()
之前将其复制到本地final
variables中。
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(); } }
当字段this.lock
是final
时候,是否有任何理由将this.lock
复制到局部variableslock
final
?
此外,它还在使用E[]
之前使用本地副本:
private E extract() { final E[] items = this.items; E x = items[takeIndex]; items[takeIndex] = null; takeIndex = inc(takeIndex); --count; notFull.signal(); return x; }
是否有任何理由将最终字段复制到本地最终variables?
这是该课程的作者Doug Lea喜欢使用的极端优化。 下面是core-libs-dev邮件列表上关于这个确切的主题的最近的一个post,它很好地回答了你的问题。
从post:
…复制到本地生成最小的字节码,对于低级代码,编写代码更接近机器
这个线程给出了一些答案。 实质上:
- 编译器不能轻易地certificate最终字段在方法内不会改变(由于reflection/序列化等)
- 大多数当前的编译器实际上不会尝试,因此每次使用时都必须重新加载最终字段,这可能导致caching未命中或页面错误
- 将其存储在本地variables中会强制JVM仅执行一次加载