为什么JDK Sourcecode命令``volatile''实例的“最终”副本



我读了有关concurrenthashmap的jdk的源代码。

但是以下代码使我感到困惑:

public boolean isEmpty() {
    final Segment<K,V>[] segments = this.segments;
    ...
}

我的问题是:

" this.segments"被声明:

final Segment<K,V>[] segments;

so,在这里,在方法的开头,声明了相同的类型参考,指向相同的内存。

作者为什么这样写?他们为什么不直接使用此发现?有一些原因吗?

这是涉及volatile变量的无锁代码的典型习惯。在第一行,您读取volatile一次,然后使用它。同时,另一个线程可以更新volatile,但您只对最初阅读的值感兴趣。

此外,即使相关的成员变量不是动荡的,但最终的变量也与CPU缓存有关,因为从堆栈位置的读取比从随机堆位置阅读的读数更友好。本地VAR最终将绑定到CPU寄存器也更高的可能性。

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

我想这是用于性能考虑的,因此我们只需要检索一次字段值。

您可以参考Joshua Bloch的有效Java的单身习惯

他的单身人士在这里:

private volatile FieldType field;
FieldType getField() {
  FieldType result = field;
  if (result == null) { 
    synchronized(this) {
      result = field;
      if (result == null) 
        field = result = computeFieldValue();
    }
  }
  return result;
}

他写道:

此代码可能看起来有些令人费解。特别是对 局部变量结果可能不清楚。这个变量的作用是 确保在常见情况下仅读取一次字段 已经初始化了。虽然并非严格必要,但这可能会有所改善 性能,根据适用于低级的标准更优雅 并发编程。在我的机器上,上面的方法约为25 百分比比没有本地变量的明显版本

它可能会减少字节代码大小 - 访问本地变量在字节代码中比访问实例变量更短。

运行时优化开销也可以减少。

,但这些都不重要。更多是关于代码样式。如果您对实例变量感到舒适,请务必一定程度。Doug lea可能感觉更自在地处理本地变量。

相关内容

最新更新