java中的單例模式
目錄
程式開發中有時候某些物件我們只需要一個,如:執行緒池、快取、對話方塊等等,對於這類物件我們只能有一個例項,如果我們製造出多個例項,就會導致很多問題產生。但是我們怎樣才能保證一個類只有一個例項並且能夠便於訪問?這裡我們想到了全域性變數,全域性變數確實是可以保證該類可以隨時訪問,但是它很難解決只有一個例項問題。最好的辦法就是讓該自身來負責儲存它的唯一例項。通過上面簡單介紹,我們可以對單例模式有一個簡單的認識。所謂單例模式就是確保某一個類只有一個例項,並且提供一個全域性訪問點。從上面可以看出單例模式有如下幾個特點:1.它只有一個例項;2.它必須要自行例項化;3.它必須自行向整個系統提供訪問點。
單例的建立模式有很多種,下面的文章中我只介紹三種方式,多餘的就不說了!
第一.餓漢式
/** * 餓漢式天生就是執行緒安全的,可以直接用於多執行緒而不會出現問題 * @author Administrator * */ public class Single1 { private static final Single1 single1=new Single1(); private Single1() { } //靜態工廠方法 public static Single1 getInstance(){ return single1; } }
第二.懶漢式
懶漢式本身是非執行緒安全的,為了實現執行緒安全有幾種寫法,分別是上面的下面的getInstance2和getInstance3,在資源載入和效能方面有些區別。
/** * 懶漢式本身是非執行緒安全的,為了實現執行緒安全有幾種寫法,分別是上面的下面的getInstance2和getInstance3,在資源載入和效能方面有些區別。 * 還有一種方法是靜態內部類,也是執行緒安全的 */ public class Single2 { private static Single2 single2=null; Single2() { } /** * 執行緒不安全 * @return */ public static Single2 getInstance(){ if(single2==null){ single2=new Single2(); } return single2; } /** * 在getInstance方法上加同步(效能較差) * @return */ public static synchronized Single2 getInstance2(){ if(single2==null){ single2=new Single2(); } return single2; } /** * 雙重檢查鎖定(DCL 雙檢查鎖機制)推薦 * @return */ public static Single2 getInstance3(){ if(single2==null){ synchronized (Single2.class){ if(single2==null){ single2=new Single2(); } } } return single2; } }
第三.靜態內部類 推薦
利用靜態內部類在原始類初始化的時候不載入的特性(只有在呼叫的時候才會載入),可以實現單例模式。
/**
* 靜態內部類 推薦
*/
public class Single3 {
private static Logger logger= LoggerFactory.getLogger(Single3.class);
private static class CrateSingle{
private static final Single3 single3=new Single3();
}
private Single3() {
}
public static final Single3 getInstance(){
return CrateSingle.single3;
}
}
總結
優點
一、節約了系統資源。由於系統中只存在一個例項物件,對與一些需要頻繁建立和銷燬物件的系統而言,單例模式無疑節約了系統資源和提高了系統的效能。
二、因為單例類封裝了它的唯一例項,所以它可以嚴格控制客戶怎樣以及何時訪問它。
缺點
一、由於單例模式中沒有抽象層,因此單例類的擴充套件有很大的困難。
二、單例類的職責過重,在一定程度上違背了“單一職責原則”。(因為單例設計模式,在程式碼getInstance書寫的過程中,有些程式碼是比較複雜的,而且會伴有一些初始化的函式,會造成該類的多種初始化或者組裝程式碼的書寫。)
下列幾種情況可以使用單例模式。
一、系統只需要一個例項物件,如系統要求提供一個唯一的序列號生成器,或者需要考慮資源消耗太大而只允許建立一個物件。
二、客戶呼叫類的單個例項只允許使用一個公共訪問點,除了該公共訪問點,不能通過其他途徑訪問該例項。