2013-05-22 113 views
2

我不確定,如果有人問過這個問題(如果真是道歉)。突變對象爲單身?

從維基百科複製的代碼。

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

    private Singleton() {} 

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

線程安全性如何?是(僅),因爲這個類沒有變異狀態?

如果我修改它像這樣

public class Singleton { 
    private static final Singleton instance = new Singleton(); 
    private FancyClass obj1; 
    private FancyClass obj2; 

    //feel free to imagine all the getters and setters for obj1 and obj2, 
    // like getObj1() and so forth 

    //tricky method 
    public void doSomething() { 
     obj1.destroyEnemy(); 
     obj2.destroyFriend(); 
    } 

    private Singleton() { 
     obj1 = null; 
     obj2 = null; 
    } 

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

我對設計模式的討論沒有興趣發生了什麼,這是什麼樣的代碼,我應該維護。是上面的'singleton'線程安全的,假設FancyClass是java標準庫類。

+0

既然你讓你的構造函數是私人的,它永遠不會被調用。所以宣佈它是空的沒有任何意義。無論如何,實例變量會自動分配默認值。 –

+0

@AniketThakur是的,這是超級愚蠢的(在構造函數中初始化爲null)。我只是重寫了一個沒有具體細節的現有課程。 – fedvasu

+0

請注意,調用'synchronized'將不會使需要多個方法調用的操作變爲線程安全。 「synchronized」「get」方法通常毫無意義。 (ObComment:可變靜態是一個非常糟糕的主意。) –

回答

3

你是對的,第一個例子是安全的,因爲沒有可變狀態。

在第二個例子中,單例並沒有做任何事情來使它成爲線程安全的,不管它是否安全取決於FancyClass是否是線程安全的。在doSomething方法上使用​​會使其線程安全。

介紹了obj1obj2 getter和setter也必須創建問題的潛力,這些都會對同一個鎖的doSomething方法同步,和你需要鎖定即使FancyClass是線程安全的,因爲如果不同線程正在改變事物,那麼這些改變需要在線程間可見。

+0

好的,根據文檔,FancyClass是線程安全的。 (JDK的一部分) – fedvasu

1

Singleton模式的設計根本不是線程安全的,只是爲了獨特而禁止創建額外的實例。代碼中線程安全的唯一部分是Singleton實例化private static final Singleton instance = new Singleton();,因爲它被調用一次類加載時間。

但有效的,如果有一個在你的類沒有成員通過以下方法修改由外部系統concurently invked,你辛格爾頓會/留ThreadSafe的

3

第一個代碼保證所有線程調用getInstance()得到一個參考到Singleton的同一個實例。

爲您實現(第二個例子),同樣是爲obj1obj2真實的,因爲雖然類本身創建類的創建是線程安全的(無法創建兩次/「並聯」他們正在創建在同一個類加載器中)。

doSomething()方法不是線程安全的。如果您需要原子操作,請將其設爲​​。

+0

我假設obj1和obj2的getter和setter也是如此,我需要讓它們同步呢? – fedvasu

+0

@fedvasu如果您只設置或獲取對象,則不需要同步。請參閱:http://stackoverflow.com/a/1351271/105224 –

0

關於你的代碼 - 既然你讓你的構造函數是私人的,它永遠不會被調用。所以宣佈它是空的沒有任何意義。無論如何,實例變量會自動分配默認值。

的所有第一代碼

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

    private Singleton() {} 

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

首先被稱爲不像你只在需要時創建實例延遲初始化早期初始化。爲了使線程安全,您需要執行以下操作:

public class Singleton { 
    private static Singleton singleInstance; 
    private Singleton() {} 
    public static Singleton getSingleInstance() { 
    if (singleInstance == null) { 
     synchronized (Singleton.class) { 
     if (singleInstance == null) { 
      singleInstance = new Singleton(); 
     } 
     } 
    } 
    return singleInstance; 
    } 

示例是延遲初始化,但概念保持不變。

+0

你忘了設置它爲volatile應該是:private static volatile Singleton singleInstance = null; –

+0

爲什麼你需要如果語句檢查相同的事情。我認爲這是一個錯誤? –

+0

@AndrewMartin不,這不是一個錯誤。它被稱爲雙重鎖定機制。這裏是[Wiki](http://en.wikipedia.org/wiki/Double-checked_locking) –