簡體   English   中英

為什么JDK源代碼采用`volatile`實例的`final`副本

[英]Why does JDK sourcecode take a `final` copy of `volatile` instances

我閱讀了JDK關於ConcurrentHashMap的源代碼。

但以下代碼讓我感到困惑:

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

我的問題是:

聲明“this.segments”:

final Segment<K,V>[] segments;

所以,在這里,在方法的開頭,聲明了一個相同的類型引用,指向相同的內存。

為什么作者這樣寫? 他們為什么不直接使用this.segments? 有什么理由嗎?

這是涉及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的可能感覺更舒服處理局部變量。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM