2012-12-19 203 views
5


我在靜態工廠方法中編寫了下面的代碼來返回DefaultCache的單個實例。工廠方法創建單例實例

public static ICache getInstance() { 
    if (cacheInstance == null) { 
     synchronized (ICache.class) { 
     if (cacheInstance == null) { 
      cacheInstance = new DefaultCache(); 
     } 
     } 
    } 
    return cacheInstance; 
} 

我們真的需要第二個空支票cacheInstance synchronized塊裏面?

+2

除了答案,看看c2.com/cgi/wiki?SingletonsAreEvil – Slauster

+0

你可能想要閱讀維基百科關於[Double-checked locking]的文章(http://en.wikipedia.org/wiki/Double_checked_locking_pattern #Usage_in_Java) –

回答

-1

有一個私人構造函數來避免所有這些檢查。

class Singleton { 
    private static final Singleton instance = new Singleton(); 

    private Singleton() { 
    } 

    public static final Singleton getInstance() { 
     return instance; 
    } 
} 
0

假設cacheInstance是靜態的,你應該考慮兩個可能的初始化策略:

  • 懶動初始化:在單場的那一刻被填入一個實例 當它第一次使用(如您例)。

  • (標準)初始化:一旦JVM加載類,單例字段將填充一個 實例。

所以,如果你打算使用惰性啓動你應該檢查無效,否則你只會返回一個空指針。

或者,您也可以在靜態塊中初始化該字段。

//class declaration 
static { 
    cacheInstance = new DefaultCache(); 
} 

或在同一行,你把它聲明

private static final DefaultCache cacheInstance = new DefaultCache(); 
4

我會避免使用延遲初始化單爭支票的需要:

public class Singleton { 
    public static ICache getInstance() { 
     return LazyCacheInitializer.INSTANCE; 
    } 

    private class LazyCacheInitializer { 
     private static final ICache INSTANCE = new DefaultCache(); 
    } 
} 
+0

這對使用'enum'有什麼好處? –

+0

這是正確的一個 – JIV

+1

@彼得那麼,關於枚舉的缺點是他們的序列化模型。枚舉只能序列化他們的名字,但不是他們的狀態。如果單身人士可以有任何一種狀態,它將會丟失。因此,具有狀態的枚舉不能通過網絡發送,或者從磁盤保存和恢復。不確定在這種特殊情況下考慮序列化單例緩存會有幫助,但是你的問題是關於優點/缺點。 –

6

您還需要第二次檢查因爲在嘗試獲取鎖定時,該值可能已由另一個線程設置。事實上,在進入同步塊之前,您無法安全地查看此值。它可能已由任何時間前的另一個線程設置。

最簡單的懶惰單是使用一個枚舉

public enum DefaultCache implements ICache { 
    INSTANCE 
} 

我假設你不這樣做,所以你可以改變實現。

順便說一句:我建議你儘可能只使用無狀態singletons,儘可能使用dependanecy注入所有有狀態的對象。

+0

爲enum +1(你比我快):) –

1

是的,否則可以創建兩個以上的實例。假設你有多個線程。第一個測試是通過比賽條件完成的,也就是說一些線程同時將變量視爲null並嘗試設置實例。沒有第二次檢查,每個線程都會創建一個新的實例。

0

您總是可以使用基於enum的單例模式實現,如Peter發佈的,但請記住,您的所有實現都是單類加載器

您還必須密切關注Cloneable接口。