我正在阅读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
,而是将其分配给局部变量?
答案 0 :(得分:11)
是否可以用于优化目的?
可能更容易使用JIT编译器将局部变量直接分配给寄存器。
至少在Android中,对于API的第一个版本,访问本地变量比访问实例变量便宜(不能代表更新的版本)。可能是普通的Java是相同的,在某些情况下,使用本地是有意义的。
实际上,找到了thread confirming this here。提取物:
这是Doug Lea流行的编码风格。这是一个极端 可能不是必要的优化;你可以期待JIT 进行相同的优化。 (您可以尝试检查机器代码 你自己!)然而,复制到当地人产生的最小 字节码,对于低级代码,编写代码很好 离机器越来越近了。
答案 1 :(得分:1)
因为它只是复制引用并且锁定在Object上,而Object是相同的,所以它应该无关紧要。
实例变量 lock 也被声明为final,所以实际上,我没有看到做引用副本的任何意义。
正如JRL所指出的那样是一种优化,但它实际上是一种微小的优化,我仍然没有看到这么做,特别是对于一次阅读。
答案 2 :(得分:0)
我想,在编写基础库时,如果它足够便宜,你最好选择最安全的解决方案。这个非常便宜。
关于性能,局部变量应该比字段访问快。我想,任何名副其实的JVM都会做这样一个简单的优化(*)本身,但是解释代码和可能的C1(Oracle JVM中的第一个,快速和低质量的编译器)呢?它不会产生太大的影响,但数百万用户可以节省微秒数。那些在JVM尚未编写的奇异平台上运行的Java呢?
final
实际上并不完全是最终的。可以使用反射更改该字段。我无法想象这样做的任何理由,任何做这些有趣事情的人都会得到他们应得的。在写这样一个基本的东西时,OTOH调试这些问题可能需要数天时间,并且防呆编程是一个好习惯。
(*)我相信已经有一位有信誉的人宣读相反的文章,但我现在找不到。