單例模式-獨一無二的物件
阿新 • • 發佈:2018-12-26
單例模式定義
確保某一個類只有一個例項,而且自行例項化並向整個系統提供這個例項,這個類稱為單例類,它提供全域性訪問的方法。
單例模式結構圖
單例模式角色介紹
單例模式只有一個角色,就是單例角色,Singleton,它自行例項化,並提供靜態方法獲取自行例項化的例項。
單例模式結構程式碼
單例類:
public class Singleton { //定義靜態變數 private static Singleton singleton; //定義私有建構函式 private Singleton(){ } public static Singleton getInstance(){ if (singleton == null){ singleton = new Singleton(); } return singleton; } }
客戶端:
public class Client {
public static void main(String[] args) {
Singleton singleton = Singleton.getInstance();
System.out.println("singleton = " + singleton);
}
}
單例模式執行緒安全問題
上述結構圖和結構程式碼在多執行緒的環境下,無法保證建立的例項全域性唯一,這樣獲取單例物件的方式並不是一個執行緒安全的方式。可以通過兩種方式解決這個問題:餓漢式單例模式和懶漢式單例模式。
餓漢式單例模式
結構圖:
結構程式碼:
public class HungrySingleton {
//定義靜態變數,類載入階段完成例項化
private static HungrySingleton singleton = new HungrySingleton();
//定義私有建構函式
private HungrySingleton(){
}
public static HungrySingleton getInstance(){
return singleton;
}
}
優缺點:
優點是簡單,類載入階段就完成了例項化,不用考慮執行緒安全問題;缺點是啟動階段效率低,一般單例類例項化都伴隨著初始化資源的操作,類載入階段完成例項化和資源初始化,影響專案啟動效率,甚至導致專案無法啟動。
懶漢式單例模式
結構圖:
結構程式碼:
public class LazySingleton {
//定義靜態變數,用volatile宣告
private volatile static LazySingleton singleton;
//定義私有建構函式
private LazySingleton(){
}
public static LazySingleton getInstance(){
synchronized (LazySingleton.class){
if (singleton == null){
singleton = new LazySingleton();
}
}
return singleton;
}
}
優缺點:
優點是既解決了執行緒安全問題,又解決了類載入階段初始化問題;缺點是多執行緒無法同時獲取單例例項,效率低。
優化的懶漢式單例模式
結構圖:
結構程式碼:
public class LazySingleton {
//定義靜態變數,用volatile宣告
private volatile static LazySingleton singleton;
//定義私有建構函式
private LazySingleton(){
}
public static LazySingleton getInstance(){
//雙重判定,提高執行緒安全模式下效率
if (singleton == null){
synchronized (LazySingleton.class){
if (singleton == null){
singleton = new LazySingleton();
}
}
}
return singleton;
}
}
此方案既解決了執行緒安全問題,又解決了多執行緒無法同時獲取單例例項的問題,屬於單例模式的完美解決方案吧。
單例模式執行機制
單例類只有私有建構函式,定義一個私有靜態成員變數指向單例例項物件,然後提供靜態方法給客戶端,實現單例類物件的例項化。
單例模式解決的核心問題
單例模式,解決的是確保全域性只存在一個例項的問題,通過自行例項化和提供的靜態方法實現。