2014-11-25 48 views
1

我想寫一個實例方法來懶惰地初始化幾個靜態變量。我初始化的對象是不可變的,對象的引用不會被類中的任何其他實例或靜態方法改變。我希望初始化代碼永遠不會被執行多次,即使在許多不同的線程中可能有多個類的實例。初始化需要在實例方法中進行,因爲該方法會覆蓋超類中的方法。我正在使用的方法如下。在多線程情況下懶惰地初始化靜態變量

private static volatile boolean isPrepared; 
private static volatile Object object1; 
private static volatile Object object2; 
private static volatile Object object3; 

@Override 
void prepare() { 
    synchronized (this.getClass()) { 
     if (isPrepared) { return; } 
     object1 = expensiveCalculation1(); 
     object2 = expensiveCalculation2(); 
     object3 = expensiveCalculation3(); 
     isPrepared = true; 
    } 
} 

我假設從初始化發生在一個synchronized塊,那將是不可能的實例來不斷觀察isPreparedtrue除非object1object2object3都是非空。我還假設它不會工作,只需聲明prepare()爲​​鎖定爲this。我的假設是正確的嗎?另外,當你想將它們視爲一起初始化時,是否有一個標記爲volatile的變量是一個好主意,還是應該將它們組合成一個Immutable類?

回答

1

捆綁所有延遲初始化狀態進入一個不可變的對象通常是優選的方法,因爲然後你需要所有volatile變量,沒有同步。如果另一個線程在初始化過程中開始初始化,那麼這種安排可以爲您帶來一些重複的努力,但是可以最小化這種機會,例如通過將標記值寫入volatile來表示「進行中」狀態。

+1

感謝您的回答。我想我會使用將變量綁定到單個易變變量的方法。但是,是不是volatile和synchronized block的組合是完全消除你提到的重複的可能性的最簡單方法? – 2014-11-25 12:40:09

+1

是的。首先檢查volatile var的值,然後根據需要輸入synchronized塊。 – 2014-11-25 12:49:35

+0

好點。如果var已經存在,你不想等待其他線程。您是否需要檢查volatile var的值兩次,一次查看是否需要同步塊,以及一次是否在塊的開頭?由於初始檢查不同步,因此在進入同步塊時,初始化可能已在另一個線程中完成。 – 2014-11-25 13:00:46