Java ConcurrentHashMap中的本地引用

Java ConcurrentHashMap中的本地引用,java,concurrency,Java,Concurrency,在ConcurrentHashMap中,段被标记为final(因此永远不会更改),但方法ensureSegment创建要操作的段的方法本地副本ss 有人知道这个目的吗?我们能得到什么好处 更新: 我从谷歌搜索,得到一个解释JDK7中ConcurrentHashMap的页面,下面是摘录 Local References 尽管段被标记为final(因此永远不会更改),Doug Lea谨慎地创建了一个方法本地副本ss,用于操作段这种防御性编程允许程序员不必担心在方法执行过程中发生易变实例成员引用的更

ConcurrentHashMap
中,段被标记为final(因此永远不会更改),但方法
ensureSegment
创建要操作的段的方法本地副本ss

有人知道这个目的吗?我们能得到什么好处

更新

我从谷歌搜索,得到一个解释JDK7中ConcurrentHashMap的页面,下面是摘录

Local References
尽管段被标记为final(因此永远不会更改),Doug Lea谨慎地创建了一个方法本地副本ss,用于操作段这种防御性编程允许程序员不必担心在方法执行过程中发生易变实例成员引用的更改(即不一致的读取)。当然,这只是一个新的引用,不会阻止方法看到引用的更改


有人能解释一下粗体文本吗?

数组被标记为
final
,但数组元素没有(不能)。因此,可以设置或替换每个数组元素,例如使用:

this.segments[i] = ...
Java 7中的
ensureSegment
使用不同的方法设置数组元素,使用
sun.misc.Unsafe
,以便在同时调用该方法时提高性能。这不是“常规”开发人员应该做的

局部变量

final Segment<K,V>[] ss = this.segments;
final Segment[]ss=this.segments;

通常用于确保(为了增加这种可能性)在该方法期间,
ss
位于CPU寄存器中,并且不会从内存中重新读取。我想在这种情况下不需要这样做,因为编译器可以推断出这一点。使用
ss
确实会使下面的行稍微短一些,可能这就是使用它的原因。

访问
final
字段和访问包含
final
字段值副本的局部变量之间没有语义上的区别。然而,在性能关键代码中,将字段复制到局部变量是一种既定模式

即使在没有区别的情况下(这取决于热点优化器的状态),它也会在方法的代码中保存至少一些字节

对实例字段的每次访问,无论是否为
final
(唯一的例外是编译时常量),都将被编译为两条指令,首先通过将
引用推送到操作数堆栈上,然后执行一个操作,该操作对描述字段的常量池项具有两字节索引。换句话说,每个字段访问都需要方法代码中的四个字节,而如果变量是方法前四个变量之一(将此计算为局部变量),则读取局部变量只需要一个字节,这里就是这种情况(请参阅)


因此,当一个字段将被多次访问时,将其值存储在一个局部变量中是一个很好的行为,可以防止可变变量的更改,并避免读取
volatile
的成本,而且即使它像
final
字段那样过时,也不会有什么坏处,因为它甚至会产生更多压缩字节码。在一个简单的解释执行中,即在优化器启动之前,单个局部变量访问可能确实比通过
这个
实例绕道更快。

链接到源代码可能会有所帮助。