2017-09-15 55 views
0

以下是仔細檢查單例模式的實現。線程A正在執行行test=new Test();但是就在同一時間,線程B首先檢查值test。對於線程B,test的值是多少?以單例模式創建對象時引用返回什麼

class Test { 
    private Test test; 
    private Test() {   
    } 
    public static Test get() { 
     if (test == null) { // Thread B. When object is being created, 
           // what's value of test. Is it always null before 
           // Thread B new object? 
      synchronized (test.getClass()) { 
       if (test == null) { 
        test = new Test(); // Thread A. This thread is creating object. 
       } 
      } 
     } 
     return test; 
    } 
} 

新增
如果它不是單例模式的一個正確的版本,可以volatile關鍵字解決這個問題?即,private volatile Test test;

+0

這必須是靜態的...:***公開測試的get(){***若不是沒有因爲你將需要一個Test類的實例,以便能夠調用get方法 –

+0

@ΦXocę웃Пepeúpaツ對不起,我對它進行了修改。 – user7328234

回答

1

它是未知的。這就是爲什麼這個實現被認爲是錯誤的。

有可能首先創建對象test = new Test()然後將它的引用分配給test,然後才初始化它。

因此,線程B將引用對象,但它可能未被初始化。

+1

此鏈接https://www.javaworld.com/article/2074979/java-concurrency/double-checked-locking-clever--but-broken.html可以很好地解釋它。 它可以避免使用資源的預先初始化。這種方法並不是一如既往,但會在這種特殊情況下消除這個問題。 – Punit

0

這其中也似乎是一個很好的方法,通過比爾普格的建議,以消除雙重檢查鎖定(如問題提到的)的缺點,我們也不需要做初始化的渴望,以及對消除此:

public class BillPughSingleton { 

    private BillPughSingleton(){} 

    private static class SingletonHelper{ 
    private static final BillPughSingleton INSTANCE = new BillPughSingleton(); 
    } 

    public static BillPughSingleton getInstance(){ 
    return SingletonHelper.INSTANCE; 
    } 
} 

請注意包含單例類的實例的private inner static class。加載單例類時,SingletonHelper class未加載到內存中,只有當有人調用getInstance方法時,纔會加載此類,並創建Singleton類實例。

這是Singleton類最廣泛使用的方法之一,因爲它不需要同步。

0

如果不是單件模式的正確版本,可以通過volatile關鍵字 來解決問題嗎?

事實上,這樣的:

private Test test; 

應該聲明:

private volatile Test test; 

否則線程的內存B可以保持test一個陳舊的版本,可能null而線程A重視與私人構造函數。

通過將test指定爲volatile,確保其他線程可以看到由一個線程執行的任何賦值。


現在這種實現單例的方式並不是非常直(雙條件語句加顯式同步)。

由於兩位漂亮的替代品,你可以使用枚舉單成語:

public enum Test implements TestInterface{ 
    SINGLETON; 
    ... 
} 

注意接口建議寫一個自然可測試的執行情況,並能夠切換到其他實現。

否則比爾普格單成語(這裏是在急於味):

public class Test{ 

    // executed as soon as the T class is loaded by the classLoader 
    private static Test instance = new Test(); 

    private Test() { 
    } 

    public static TestgetInstance() { 
     return instance; 
    } 
} 
相關問題