在使用之前复制对局部变量的引用很重要 [英] Is it important to copy a reference to a local variable before using it

查看:215
本文介绍了在使用之前复制对局部变量的引用很重要的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在OpenJDK 8中探索java.util.LinkedList的代码,我找到了以下代码。代码很简单,但我很困惑将第一个节点的引用保存到第二行代码中的常量。据我所知,这段代码将被内联到单行内容而无需参考复制。我对吗?如果是这样,为什么需要在此类似情况下复制引用(这种习惯用法可以在java.util.LinkedList的一半方法中找到)?

Exploring the code of java.util.LinkedList as it is in OpenJDK 8, I found the following code. The code is straightforward, but I'm confused about saving reference to the first node to a constant in the second line of code. As far as I understand, this code will be inlined to one-liner without reference copying. Am I right? If so, why does one need to copy reference in this and similar situations (such idiom may be found in a half of methods in java.util.LinkedList)?

public E peek() {
    final Node<E> f = first;
    return (f == null) ? null : f.item;
}

我的第一个想法是它以某种方式帮助并发,但LinkedList没有允许并发访问(除了你自己承担风险),所以我想这是优化器的一些提示,但无法弄清楚它应该如何工作。

My first thought was that it helps concurrency in some way, but LinkedList does not allow concurrent access (except at your own risk), so I guess it is some hint for optimizer, but can't figure out how it is supposed to work.

推荐答案


我的第一个想法是它以某种方式帮助并发...

My first thought was that it helps concurrency in some way...

...所以我猜测它是优化器的一些提示...

...so I guess it is some hint for optimizer...

两者。 :-) LinkedList 不支持并发的事实并不意味着作者无论如何都不会遵循良好的做法,它告诉编译器和JIT他们应该只查看首先 一次

Both. :-) The fact that LinkedList doesn't support concurrency doesn't mean that the authors aren't going to follow good practices anyway, and it tells the compiler and the JIT that they should only look up first once.

没有 f 本地变量,我们有:

Without the f local variable, we'd have:

public E peek() {
    return (this.first == null) ? null : this.first.item;
}

我添加了隐含的这个。强调第一个是一个实例字段。

I've added the implied this. to emphasize that first is an instance field.

所以如果 this.first == null part在线程A上进行评估,然后 this.first 在线程B上更改,当 this.first.item 在线程A上进行评估,因为 this.first 已成为 null 在此期间。 f 是不可能的,因为 f 是本地的;只有运行 peek 调用的线程才会看到它。

So if the this.first == null part is evaluated on Thread A, then this.first is changed on Thread B, when this.first.item is evaluated on Thread A, it may throw because this.first has become null in the meantime. That's impossible with f, because f is local; only the thread running the peek call will see it.

final part既是良好的代码内文档(因为作者从不打算改变 f 的值),也提示优化器我们永远不会去改变 f ,这意味着当需要进行优化时,它可以将其优化到其生命的一英寸范围内,因为它知道它只需读取 this.first 一次,然后可以使用 null 检查的寄存器或堆栈值返回。

The final part is both good in-code documentation (as the author never intends to change the value of f) and a hint to the optimizer that we're never going to change f, which means that when it comes time to optimize, it can optimize it to within an inch of its life, knowing that it only ever has to read this.first once and can then use a register or stack value for both the null check and the return.

这篇关于在使用之前复制对局部变量的引用很重要的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆