2013-02-02 147 views
0

創建已經保存爲成員字段的靜態易失性變量的本地引用的目的或價值是什麼。此代碼來自java.util.Scanner JDK 6b14 here用於訪問易失性實例變量的局部變量

class Scanner { 
    private static volatile Pattern linePattern; 
    ... 
    private static Pattern linePattern() { 
     Pattern lp = linePattern; 
     if (lp == null) 
      linePattern = lp = Pattern.compile("..."); 
     return lp; 
    } 
    ... 
} 

The Java Tutorials:「讀取和寫入原子的所有變量聲明爲volatile(包括長和雙變量)......到volatile變量任何寫入建立之前發生同一個變量的隨後關係讀取。 「

這意味着讀取Pattern對象的引用不會因爲它已經改變而中途失敗。 volatile關鍵字應該保護這些類型的訪問,所以我不重複的局部變量是爲了確保返回有效的值。

而且,延遲初始化可以在成員字段來完成,而不需要中間的局部變量:

if (linePattern == null) linePattern = Pattern.compile("..."); 

這看起來是一個字節碼優化,看到herehere。使用本地變量會產生較小的字節碼(較少的指令)以及較少的對實際值的訪問(這是一種昂貴的易失性讀取)。但是他們還沒有使用最終的變量優化,所以我對得出這個結論持懷疑態度。

回答

1

這個「加速」起來的東西。訪問volatile變量是昂貴的。使用可以通過將其分配給堆棧變量並訪問該開銷,而不是使用

2

Lazy initialization,即延遲工作直到真正有必要。

+0

但爲什麼不只是懶惰地初始化成員字段? – xst

+0

該方法完全封裝。它用於獲取該字段的值並確保在需要時進行初始化。 – Wormbo

+0

'if(linePattern == null)linePattern = new ...'這會懶惰地初始化成員字段而不是局部變量。 – xst

0

對於volatile字段,linePattern可能會在不同的行之間發生變化。將引用複製到局部變量可以確保您不能有不一致的狀態。例如,如果你寫

if (linePattern == null) 
    linePattern = Pattern.compile("..."); 

然後linePattern可能有停止Pattern.compile正在執行被空。

+0

揮發性關鍵字保證讀取不重疊,正如參考文獻(我剛剛添加)中所述。您是否指C中的volatile,它用於讀取內存映射的IO設備? – xst

+0

不,我非常明確地指Java中的volatile。你所說的引用意味着'linePattern'不會在一個特定的讀或者一個特定的寫中間重疊,但是如果你正在做多次讀和/或多次寫操作,這個值可以被其他線程這些行動之間。 –

1

它保證返回值不爲NULL - 即使靜態變量在檢查和返回之間設置爲NULL。

同時,它是一個非同步的惰性初始化,如果需要,可以重新初始化;)。