設計模式之---單例模式,設計模式之---模式
設計模式的世界中,單例模式可能是最簡單的一種模式,雖說簡單,但想要徹底的弄明白它,還是要經曆一點點的波折。
下面我為大家慢慢道來:
在實際開發中,對於有些對象,我們只需要一個,比如線程池(thread pool),緩衝(cache),對話方塊,日誌對象,工作管理員等等。這些對象只能有一個執行個體,如果出現多個執行個體,則會導致許多問題的產生。
你可能會說,我們為什麼不用java的全域變數,多方便的。是的,但是這樣做是有缺點的,如果我們將一個對象賦值給一個全域變數,那麼我們在程式一開始就必須建立好對象,一旦這個對象非常耗費資源,而程式在執行中又一直沒有用到它,那麼這樣是非常的浪費。
單例模式,要保證一個對象只能被執行個體化一次,我們先來看一段雛形代碼:
public class Singleton {private static Singleton uniqueInstance;private Singleton(){}public static Singleton getInstance(){if(uniqueInstance==null){uniqueInstance = new Singleton();}return uniqueInstance;}}
在這裡,我們利用一個靜態變數來記錄Singleton類的唯一執行個體,並把構造方法設定為私人,那麼只有在Singleton類內部才可以調用此構造方法。然後我們用getInstance()方法執行個體化對象,並返回這個執行個體。如果uniqueInstance是空的,表示還沒有建立執行個體,如果不為空白,表示之前已經建立過對象,則直接跳過至return語句。
但是仔細想想,就會發現,上面的代碼是有些問題的,問題在哪裡呢?
如果我們想應用多線程,那麼如果有兩個或兩個以上的線程要執行上面這段代碼,則可能會出現產生多個執行個體對象的情況,也就是說,沒有同步機制,可能兩個線程都執行到了uniqueInstance==null的情況,那麼之後就會產生兩個object,而這樣的結果就是不對的。
這是你可能會說,給方法加synchronized關鍵字啊,是的,於是有了下面的代碼:
public class Singleton {private static Singleton uniqueInstance;private Singleton(){}public static synchronized Singleton getInstance(){if(uniqueInstance==null){uniqueInstance = new Singleton();}return uniqueInstance;}}
這樣,我們通過增加synchronized關鍵字到getInstance()方法中,可以使得每個線程在進入這個方法之前,要先等候別的線程離開該方法。也就是說不會有兩個線程可以同時進入該方法。
但是這樣做的問題是什嗎?仔細想想,很簡單,那就是:同步會降低效能
也就是說,我們只有第一次執行此方法的時候才需要同步,一旦設定好了uniqueInstance變數,就不再需要同步這個方法了,因為只有第一次unqueInstance==null,之後每次調用這個方法,同步都是多餘的,甚至是一種累贅。
所以,有時候要根據情況靈活的應對。
如果getInstance()的效能對應用程式不是很重要,那就什麼都別做,但是必須要知道的是,同步一個方法可能會造成程式執行的效率下降100倍,所以很多時候,我們就要重新考慮了。
當然,如果我們有時很急切的需要建立執行個體,而不用延遲執行個體化的做法,就是在靜態初始化器中建立單例,如下面的代碼:
public class Singleton {private static Singleton uniqueInstance=new Singleton();private Singleton(){}public static synchronized Singleton getInstance(){return uniqueInstance;}}
而且這段代碼是安全執行緒的。
下面我們來看單例模式的最終版:
雙重檢查加鎖,在getInstance()中減少使用同步:
利用雙重檢查加鎖(double-checked locking),首先檢查是否執行個體已經建立了,如果未建立,才進行同步,這樣,只有第一次會同步,而這正是我們想要的:
public class Singleton {private volatile static Singleton uniqueInstance;private Singleton(){}public static Singleton getInstance(){if(uniqueInstance==null){synchronized (Singleton.class){if(uniqueInstance==null){uniqueInstance = new Singleton();}}}return uniqueInstance;}}
volatile關鍵字,用來確保將變數的更新操作通知到其他線程,保證新值能立即同步到主記憶體,以及每次使用前立即從主記憶體重新整理。當把變數聲明為volatile後,編譯器與運行時都會注意到這個變數是共用的。
在這裡,volatile關鍵字確保了,當uniqueInstance變數被初始化成Singleton執行個體時,多個線程能正確的處理uniqueInstance變數。
如果效能是你關係的重點,那麼這個做法可以幫你大大減少getInstance()的時間耗費。
什是單例設計模式
java模式之單例模式:
單例模式確保一個類只有一個執行個體,自行提供這個執行個體並向整個系統提供這個執行個體。
特點:
1,一個類只能有一個執行個體
2,自己建立這個執行個體
3,整個系統都要使用這個執行個體
例: 在下面的對象圖中,有一個"單例對象",而"客戶甲"、"客戶乙" 和"客戶丙"是單例對象的三個客戶對象。可以看到,所有的客戶對象共用一個單例對象。而且從單例對象到自身的連接線可以看出,單例對象持有對自己的引用。
Singleton模式主要作用是保證在Java應用程式中,一個類Class只有一個執行個體存在。在很多操作中,比如建立目錄 資料庫連接都需要這樣的單線程操作。一些資源管理員常常設計成單例模式。
外部資源:譬如每台電腦可以有若干個印表機,但只能有一個Printer Spooler,以避免兩個列印工作同時輸出到印表機中。每台電腦可以有若干個通訊連接埠,系統應當集中管理這些通訊連接埠,以避免一個通訊連接埠被兩個請求同時調用。內部資源,譬如,大多數的軟體都有一個(甚至多個)屬性檔案存放系統配置。這樣的系統應當由一個對象來管理這些屬性檔案。
一個例子:Windows 資源回收筒。
在整個視窗系統中,資源回收筒只能有一個執行個體,整個系統都使用這個惟一的執行個體,而且資源回收筒自行提供自己的執行個體。因此,資源回收筒是單例模式的應用。
兩種形式:
1,餓漢式單例類
public class Singleton {
private Singleton(){}
//在自己內部定義自己一個執行個體,是不是很奇怪?
//注意這是private 只供內部調用
private static Singleton instance = new Singleton();
//這裡提供了一個供外部存取本class的靜態方法,可以直接存取
public static Singleton getInstance() {
return instance;
}
}
2,懶漢式單例類
public class Singleton {
private static Singleton instance = null;
public static synchronized Singleton getInstance() {
//這個方法比上面有所改進,不用每次都進行產生對象,只是第一次
//使用時產生執行個體,提高了效率!
if (instance==null)
instance=new Singleton();
return instance; }
}
第二中形式是lazy initialization,也就是說第一次調用時初始Singleton,以後就不用再產生了。...餘下全文>>
java 單例模式(單一設計模式)怎保證的只可以產生一個執行個體?更具體的解釋
我覺得這個注釋已經說得很清楚了,GOF的23種設計模式說得很清楚,單例,就是一個Class在一個Classloader中只有一個執行個體。在類中寫一個私人的構造器,那麼除了自己,在其他類中都無法建立這個類的執行個體,其中有一個靜態域也就是自己的執行個體,由自己NEW出來的,其中的可以被其他類訪問的靜態方法只是返回這個執行個體,而不會去再New,所以保證了不能再建立第二個!