[英]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.