2
public E poll() {
    final AtomicInteger count = this.count;
    if (count.get() == 0)
        return null;
    E x = null;
    int c = -1;
    final ReentrantLock takeLock = this.takeLock;
    takeLock.lock();
    try {
        if (count.get() > 0) {
            x = dequeue();
            c = count.getAndDecrement();
            if (c > 1)
                notEmpty.signal();
        }
    } finally {
        takeLock.unlock();
    }
    if (c == capacity)
        signalNotFull();
    return x;
}

谁能解释为什么我们将 this.count 分配给局部变量,以及为什么将局部变量声明为 final?

4

3 回答 3

2

谁能解释为什么我们将 this.count 分配给局部变量

它可能会潜在地提高性能,因为访问局部变量比访问实例变量要便宜一些。这篇文章似乎支持这一点。然而,他们也说这是一种极端的优化,可能没有必要。

还有为什么局部变量声明为final?

似乎该字段count也是final源代码中定义的。他们可能只想通过将局部变量声明为 来保持一致final

于 2013-10-23T20:42:10.283 回答
0

我在执行以下操作时可以看到的唯一价值:

final AtomicInteger count = this.count;

和:

final ReentrantLock takeLock = this.takeLock;

是:如果原始成员未声明为最终成员,并且作者想向将来维护此代码的程序员发出信号 - 无论如何不要更改对这些对象的引用(这是通过final声明实现的)。

更新:
此代码取自Doug Lea 编写的LinkedBlockingQueue的实现。根据assylias 上面发布的链接,Marko 写道:

此外,即使所讨论的成员变量不是 volatile 而是 final,这个习惯用法也与 CPU 缓存有关,因为从堆栈位置读取比从随机堆位置读取对缓存更友好。本地 var 最终绑定到 CPU 寄存器的可能性也更高。

对于后一种情况,实际上存在一些争议,因为 JIT 编译器通常会处理这些问题,但 Doug Lea 是坚持一般原则的人之一。

于 2013-10-23T18:27:45.520 回答
0

我确信它与各种编译器优化有关。一般来说,像这样的编译器提示是不必要的,因为理论上编译器应该能够自己解决这个特定的优化问题,但是 JDK 编写者可能对编​​译器的实际实际实现有更好的了解,因此知道这将创建更快的字节码。

于 2013-10-23T18:45:26.103 回答