ArrayBlockingQueue中,所有需要锁定的方法在调用final之前将其复制到本地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();
    }
}

当字段this.locklock时,是否有理由将this.lock复制到本地变量final? br />另外,在执行操作之前,它还会使用E[]的本地副本:
private E extract() {
    final E[] items = this.items;
    E x = items[takeIndex];
    items[takeIndex] = null;
    takeIndex = inc(takeIndex);
    --count;
    notFull.signal();
    return x;
}

是否有任何理由将final字段复制到本地final变量?

#1 楼

该类的作者Doug Lea喜欢使用这种极端的优化方法。这是有关core-libs-dev邮件列表的最新主题的相关帖子,可以很好地回答您的问题。

来自帖子:


...复制到本地会产生最小的
字节码,对于低级代码,最好编写与计算机更近的代码



评论


强烈强调“极端”!这不是每个人都应该模仿的通用的良好编程习惯。

– Kevin Bourrillion
2010年5月7日13:42

随机FYI:在其他情况下,当您看到此操作完成时,这是因为所讨论的字段是易变的,并且该方法需要确保它始终具有单个一致的值或参考。

– Kevin Bourrillion
2010年5月7日13:44

我将在这样的核心类中进行这种“极端”优化。

–埃里克·罗伯逊(Erick Robertson)
2011年1月13日12:58

@zamza,局部最终变量仅由Java编译器使用,而不由字节码使用(即JVM不知道局部变量是否为最终变量)

– bestsss
2011年11月6日,下午1:32

除了字节码大小之外,这是否还优化了执行速度?

– SantiBailors
17年2月9日在9:08

#2 楼

该线程给出了一些答案。本质上:


编译器不能轻易证明方法中的final字段不变(由于反射/序列化等)。
当前大多数编译器实际上并没有这样做不要尝试,因此每次使用时都必须重新加载最终字段,这可能导致高速缓存未命中或页面错误
将其存储在局部变量中会强制JVM仅执行一次加载


评论


我认为JVM不必重新加载最终变量。如果通过反射修改了最终变量,则无法保证程序正常运行(这意味着在所有情况下都可能不会考虑新值)。

–icza
2014年10月1日下午6:35