2013-03-18 142 views
1

這兩個班是一樣的嗎?是否正在實例化非最終靜態變量線程安全?

public class SingleTone { 

    // yes this is a bug what if i change the class this way 
    // private static SingleTone instance = new SingleTone(); 
    // and empty constructor? 
    private static SingleTone instance; 
    private SingleTone() { 
     instance = new SingleTone(); 
    } 

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

public class SingleTone { 

    private final static SingleTone instance = new SingleTone(); 

    private SingleTone() { 
    } 

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

是在有最終沒有任何變化線程安全問題,通過構造函數實例?

問題2:

什麼

private final static SingleTone instance = new SingleTone(); 

    private SingleTone() { 
    } 

,這之間的差異:

private final static SingleTone instance; 

    private SingleTone() { 
     instance = new SingleTone(); 
    } 
+0

爲了澄清更多:如果我這樣重寫我的第一個例子私有靜態SingleTone實例=新SingleTone();並刪除構造函數實例!什麼是使用最終的好處! (我正在尋求線程安全問題而不是性能) – 2013-03-18 12:17:08

+1

您問題的原始版本的兩個部分都包含錯誤。而你的「澄清」問題現在如此令人困惑/混亂,以至於無法迴避......國際海事組織。 – 2013-03-18 12:18:01

+0

可以回答的一點是:有或沒有'最終'字段*有效最終*,因爲它被保證只能分配一次。它是線程安全的,因爲分配發生在類初始化時。 – 2013-03-18 12:19:55

回答

2

Queston 1個

你的第一個例子不工作。

就好像你撥打這個電話SingleTone.getInstance()該類型已創建的對象的時候,才返回null

第二個例子正常工作

問題2

同樣的情況,你就是instatiating一構造函數中的靜態字段。這是沒有意義的,因爲你不能保證在訪問靜態字段之前調用構造函數。

你可以這樣做,而不是:

private final static SingleTone instance; 

static { 
    instance = new SingleTone(); 
} 

這將實例化靜態字段第一次加載類時。


回答您的評論。

如果你這樣做:

private static final SingleTone instance = new SingleTone(); 

這是線程安全的,就好像第一個線程處理不當完成初始化類,而另一個線程試圖訪問它的其他線程將被阻塞。

更多信息,請參閱這個問題:Thread safety of static blocks in Java

+0

是的,你是正確的,如果我重寫我的第一個例子這樣private static SingleTone instance = new SingleTone();並刪除構造函數實例!什麼是使用最終的好處! (我正在尋求線程安全問題不是性能) – 2013-03-18 12:14:51

+0

更新的答案根據您的評論 – cowls 2013-03-18 12:21:27

+0

謝謝我得到了錯誤!然而在我的評論中,我沒有使用最終變量而不是最終變量。我更新了答案,請再看一遍 – 2013-03-18 12:37:42

0

兩個選項實際上都是相同的(但super()呼叫的構造在這兩種情況下丟失)。

但是,實現一個singleton是使用私有靜態字段的Java往往被棄用。現在,我會使用枚舉。

public enum Elvis { 
    INSTANCE; 
    private final String[] favoriteSongs = 
     { "Hound Dog", "Heartbreak Hotel" }; 

    public void printFavorites() { 
     System.out.println(Arrays.toString(favoriteSongs)); 
    } 
} 

如果你想進一步閱讀:http://www.drdobbs.com/jvm/creating-and-destroying-java-objects-par/208403883?pgno=3

+0

我不要求執行單音我知道枚舉方式。 – 2013-03-18 12:21:18

0

SingleTone類必須返回一個參考,所以第一個例子是完全錯誤的。

考慮以下過程: 由JVM 開始1.類加載2.類被裝入JVM。 3.構造執行 4.對象創建完成

公共類SingleTone { 對於這個例子實例將活1個2 私人最終靜態SingleTone實例之間=新SingleTone();

private SingleTone() { 
} 

public static SingleTone getInstance(){ 
    return instance; 
} 

}

公共類SingleTone { 對於這個例子實例將在3和4 私人最終靜態SingleTone實例之間活着;

private SingleTone() { 
    instance = new SingleTone(); 
} 

public static SingleTone getInstance(){ 
    return instance; 
} 

}