2012-08-08 46 views
2

請詳細介紹一下關於雙重檢查單身人士的問題..!它有什麼優點和缺點.. !!我有這個下面class..How我可以把它作爲一個雙重檢查單..關於雙重檢查單身人士

private DataBaseDAO() { } 
     public static synchronized DataBaseDAO getInstance() { 
      if (dao == null) { 
       dao = new DataBaseDAO(); 
       } 
      return dao; 
      } 
     } 
    } 
+1

看到這個偉大的職位雙重檢查單身人士:http://www.ibm.com/developerworks/java/library/j-dcl/index.html – 2012-08-08 16:38:30

+1

雙重檢查鎖定習語的主要缺點:它是壞的,除非你讓道易變。不要使用它。 – assylias 2012-08-08 16:54:46

回答

3

考慮下面的代碼

public static Singleton getInstance() 
{ 
    if (instance == null) 
    { 
    synchronized(Singleton.class) { //1 
     if (instance == null)   //2 
     instance = new Singleton(); //3 
    } 
    } 
    return instance; 
} 

背後雙重檢查鎖定理論是第二檢查在// 2使得它不可能用於兩個不同的Singleton對象作爲發生清單

考慮以下的事件序列中創建:

線程1進入getInstance()方法。

線程1在// 1處進入同步塊,因爲實例爲空。

線程1被線程2

線程2進入getInstance()方法搶佔。

線程2嘗試獲取// 1處的鎖,因爲實例仍爲空。但是,因爲線程1保持鎖定,所以線程2在// 1處阻塞。

線程2被線程1

線程佔先1個執行並因爲實例仍然空在// 2,創建一個Singleton對象並分配其參考實例。

線程1退出synchronized塊並從getInstance()方法返回實例。

線程1是由線程搶佔2.

線程2在// 1,並檢查獲得鎖,以查看是否實例爲null。

由於實例非空,因此不會創建第二個Singleton對象,並返回由線程1創建的對象。

雙重鎖定鎖定理論是完美的。不幸的是,現實是完全不同的。雙重檢查鎖定的問題是不能保證它可以在單處理器或多處理器的機器上工作。 雙重檢查鎖定失敗的問題不是由於JVM中的實現錯誤,而是由於當前的Java平臺內存模型。內存模型允許所謂的「無序寫入」,這是這個習慣用法失敗的主要原因。

+0

如果這種模式不起作用,你會建議另一種成語嗎? – Windle 2012-08-08 16:41:19

+0

@Windle這將爲你工作 – 2012-08-08 16:45:04

0

在您的代碼實現中,您正在執行靜態方法級別同步。如果DatabaseDAO類中有其他靜態方法,那麼即使這些方法可以獨立使用這些方法,它們也將無法使用。你可以通過塊級同步來避免這種情況。在多線程應用程序,這是最安全的方法之一來實現singleton對象 -

private DataBaseDAO { 
    private static final Object lock = new Object(); 
    private static DataBaseDAO dao = null; 
    private DataBaseDAO() { } 
    public static DataBaseDAO getInstance() { 
     if (dao == null) { 
      synchronize(lock) { 
       if (dao == null) { 
        dao = new DataBaseDAO(); 
       } 
      } 
     } 
     return dao; 

    } 
} 

作爲一個對象鎖定你也可以使用DataBaseDAO.class

說明:多個線程同時訪問getInstance()方法。在交錯場景中,2個或更多線程可以通過第一個if檢查,但只有一個線程將獲取對象lock的鎖定。獲取鎖的線程將能夠創建實例。其他線程,即使已經通過第一個if檢查,如果第一個線程已經獲取它(並且第一個線程尚未釋放它),將無法獲得鎖定。

現在,說第一個線程釋放了鎖,這意味着它也已經實例化了dao對象。當調度其他線程時,每個線程都會獲得該鎖,但第二個if檢查將失敗並立即釋放該鎖並獲取已經實例化的dao對象。

一旦創建了對象,以後所有嘗試訪問getInstance()方法的線程將不會進行任何同步,因爲第一個if本身將失敗。

+0

@ gotuskar..please解釋第二行的使用..that是..私人靜態最終對象鎖=新的對象(); ..請解釋它的功能 – user1582269 2012-08-08 16:43:04

+0

-1這是你不應該做的一個很好的例子。這是一個破碎的設計。 – assylias 2012-08-08 16:44:55

+0

@assylias可以請你更新最好的設計 – user1582269 2012-08-08 16:46:14

3

一個好的解決方案,如在"Effective Java Second Edition"所描述的,是使用 「單例-AS-枚舉」 圖案:它經由DataBaseDAO.INSTANCE

public enum DataBaseDAO() { 
    INSTANCE; 
} 

和訪問。這可以保證在所有情況下都會有且僅有一個DataBaseDAO的實例。

+1

+1這是正確的做法。 – assylias 2012-08-08 16:45:42