2011-07-07 93 views
2

2線以下的代碼在多線程環境中有何不同?多線程中的單例 - 各種場景

代碼1:

public class Singleton { 
private Singleton() {} 

private static class SingletonHolder { 
    private static final Singleton INSTANCE = new Singleton(); 
} 

public static Singleton getInstance() { 
    return SingletonHolder.INSTANCE; 
} 
} 

代碼2:

class Singleton { 
private static Singleton uniqueInstance; 

private Singleton() { ... } 

public static Singleton getInstance() { 
    if (uniqueInstance == null) { 
     uniqueInstance = new Singleton(); 
    } 

    return uniqueInstance; 
} 
} 

爲什麼代碼2不會在多線程環境中工作,當它也已經聲明爲static變量,將得到一次加載類加載&因此它只有一個實例?

謝謝!

回答

4

請記住,在給定的時間,多於一個線程可以調用getInstance

在示例1中,uniqueInstance成員的初始化程序保證只在類加載時運行一次。

在實施例2中,由於初始化發生直列在getInstance,多於一個的線程可以獨立地和同時地找到uniqueInstance成員變量是null。然後,每個線程將調用new Singleton(),其中取決於兩個(或更多)線程的時間的不確定結果。

對於示例2的工作,您可以(例如)在getInstance方法上添加​​。

你關於變量爲在類裝入時間充分初始化評論是真實的實施例1,但不爲2 - 實施例2中的成員變量在類裝入時間設定爲null,但與對象實例填充之後,在第一次調用getInstance期間。

+0

如果我從示例2中刪除空檢查條件會怎麼樣?在這種情況下,當多線程嘗試調用getInstance()時,它會看到第1個線程已經初始化它,對嗎?那麼,爲什麼我們說例2不是線程安全的呢? – Mike

+0

這會讓事情變得更糟,因爲單身人士的每個用戶都會得到他們自己的班級實例。該檢查是必需的,但必須以線程安全的方式進行,通常使用'synchronized'。 –

+0

但我宣佈它爲靜態&不是靜態應該只加載一次? – Mike

1

多個線程可以是內:同時

if (uniqueInstance == null) { 
... 
} 

條件。