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

时间:2011-10-30 07:26:59

标签: java

我正在阅读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,而是将其分配给局部变量?

3 个答案:

答案 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调试这些问题可能需要数天时间,并且防呆编程是一个好习惯

(*)我相信已经有一位有信誉的人宣读相反的文章,但我现在找不到。