为什么它不直接使用实例字段,而是将其分配给局部变量?

我正在阅读java.util.concurrent.ArrayBlockingQueue的源代码,发现了一些我不理解的代码:

 private final ReentrantLock 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(); } } 

注意这一行:

 final ReentrantLock lock = this.lock; 

为什么它不直接使用this.lock ,而是将它分配给局部变量?

它可以用于优化目的吗?

可能更容易使用JIT编译器将局部变量直接分配给寄存器。

至少在Android中,对于API的第一个版本,访问本地变量比访问实例变量便宜(不能代表更新的版本)。 可能是普通的Java是相同的,在某些情况下使用本地是有意义的。

实际上,在这里找到了一个证实这一点的线索 。 提取:

这是Doug Lea流行的编码风格。 这是一种极端的优化,可能不是必需的; 您可以期望JIT进行相同的优化。 (您可以尝试自己检查机器代码!)然而,复制到本地生成最小的字节码,而对于低级代码,编写更接近机器的代码是很好的。

因为它只是复制引用而锁是在Object上,而Object是相同的,所以它无关紧要。

实例变量也被声明为final,所以实际上,我没有看到做引用副本的任何意义。

正如JRL所指出的那样是一种优化,但它实际上是一种微小的优化,我仍然没有看到这么做,特别是对于一次读取。

比抱歉更安全吗?

我想,在编写基础库时,如果它足够便宜,你最好选择最安全的解决方案。 而且这个非常便宜。

  • 关于性能,局部变量应该比字段访问更快。 我想,任何名副其实的JVM都会做这样一个简单的优化(*)本身,但是解释代码和可能的C1(Oracle JVM中的第一个,快速和低质量的编译器)呢? 它不会有太大的区别,但数百万用户所节省的微秒数。 如何在具有JVM的异域平台上运行Java呢?

  • 实际上, final并非完全是最终的。 可以使用reflection更改该字段。 我无法想象这样做的任何理由,任何做这些有趣事情的人都会得到他们应得的。 OTOH调试此类问题可能需要数天时间,而且在编写这样一个基本内容时,简单的编程是一个好习惯


(*)我相信有一个有声望的人宣读相反的文章,但我现在找不到它。