java之設計模式-單例模式
1.定義:指一個類只有一個例項,且該類能自行建立這個例項的一種模式。例如,Windows只能開啟一個工作管理員,這樣可以避免因開啟多個工作管理員視窗而造成記憶體資源的浪費,或出現各個視窗顯示內容不一致等錯誤。
例如:windows的回收站,作業系統中的檔案系統,多執行緒中的執行緒池,印表機的後臺處理服務,應用程式的日誌物件,資料庫的連線池,網站的計數器,web應用的配置物件,應用程式的對話方塊?
單例模式的特點:
a.單例類只有一個例項物件;
b.該單例物件必須由單例類自行建立;
c.單例類對外提供一個訪問該單例的全域性訪問點。
2.單例模式的結構與實現
單例模式是設計模式中最簡單的模式之一,通常,普通類的建構函式是共公有的,外部類可以通過“new 建構函式()”來生成多個例項。但是,如果將類的建構函式設為私有的,外部類就無法呼叫該建構函式,也就無法生成多個例項。這時該類自身必須定義一個靜態私有例項,並向外提供一個靜態的共有函式用於建立或獲取該靜態私有例項。
2.1 單例模式的結構
單例模式的主要角色如下:
2.2 單例模式的實現方式
步驟其實都是3步:
1.首先他不能被外部類例項化,所以構造方法必須用private關鍵字,第一步就是先寫一個私有的構造方法。
private Singleton(){ };
2.因為只能自己例項化自己,所以,要自己建立一個物件。以下哪個都可以,一個屬於懶漢式,一個屬於餓漢式。
private static Singleton instance; //懶漢式
private static HungrySingleton instance = new Singleton(); //餓漢式
3.要想外部訪問到這個物件,那麼必須定義一個public方法,這樣把自己建立的物件傳進去,讓外部類使用才可以。
public static Singleton getInstance()
{return instance;}
第一種,懶漢:該模式的特點是因為比較懶,類載入時沒有生成單例,只有當第一次呼叫getInstance方法時才去建立這個單例。程式碼如下:
執行緒不安全的:因為沒有加鎖 synchronized,所以嚴格意義上它並不算單例模式。
這種方式 lazy loading 很明顯,不要求執行緒安全,在多執行緒不能正常工作。 public class LazySingleton { private LazySingleton(){ } private staticLazySingleton instance; public static LazySingleton getInstance(){ if(instance == null){ instance = new LazySingleton(); } return instance; } }
描述:這種方式具備很好的 lazy loading,能夠在多執行緒中很好的工作,但是,效率很低,99% 情況下不需要同步。 優點:第一次呼叫才初始化,避免記憶體浪費。 缺點:必須加鎖 synchronized 才能保證單例,但加鎖會影響效率。 getInstance() 的效能對應用程式不是很關鍵(該方法使用不太頻繁)。 public class Singleton { private static Singleton instance; private Singleton (){} public static synchronized Singleton getInstance() { if (instance == null) { instance = new Singleton(); } return instance; } }
第二種,餓漢式:直接建立物件,不管你有沒有用,反正提前建立好了。就和怕餓著一樣,先準備好吃的再說。
public class HungrySingleton { private HungrySingleton(){ } private static HungrySingleton instance = new HungrySingleton(); public static HungrySingleton getInstance(){ return instance; } }
測試以上的是不是同一個物件:結果顯示物件地址都一樣,是同一個。
import org.testng.annotations.Test; public class TestModel { @Test public void test() { HungrySingleton hungrySingleton = HungrySingleton.getInstance(); HungrySingleton hungrySingleton1 = HungrySingleton.getInstance(); System.out.println(hungrySingleton); System.out.println(hungrySingleton1); System.out.println(hungrySingleton == hungrySingleton1); assert hungrySingleton == hungrySingleton1; } @Test public void test1() { LazySingleton lazySingleton = LazySingleton.getInstance(); LazySingleton lazySingleton1 = LazySingleton.getInstance(); System.out.println(lazySingleton); System.out.println(lazySingleton1); System.out.println(lazySingleton == lazySingleton1); assert lazySingleton == lazySingleton1; } }
第三種:雙檢鎖/雙重校驗鎖(DCL,即 double-checked locking)
描述:這種方式採用雙鎖機制,安全且在多執行緒情況下能保持高效能。 getInstance() 的效能對應用程式很關鍵。 public class Singleton { private volatile static Singleton singleton; private Singleton (){} public static Singleton getSingleton() { if (singleton == null) { synchronized (Singleton.class) { if (singleton == null) { singleton = new Singleton(); } } } return singleton; } }
其他的參考:https://www.runoob.com/design-pattern/singleton-pattern.html