java設計模式(單例模式)的效能及思想
單例模式:
單例模式是設計模式中使用最普遍的模式之一,是一種物件建立模式,用於生產一個物件的具體例項,塔可以確保系統中一個類只產生一個例項.那麼在java中有什麼好處呢? 接下來我們一起分析下
一:對於頻繁使用的物件,可以省略建立物件所花費的時間,這對重量級物件是一筆系統開銷.
二:由於new操作的次數減少,因而對系統記憶體的使用頻率也會降低,減輕了GC的壓力,多段GC停頓時間.
因此對於系統的關鍵元件被頻繁使用物件,使用單例模式便可以有效地改善系統的效能,單例模式非常簡單,只有單例類和使用者
我們看下單例模式實現程式碼
public class Singleton {
private Singleton() {
System.out.println("Singleton 建立");
}
private static Singleton instance = new Singleton();
private static Singleton getInsSingleton() {
return instance;
}
}
注意一下單例模式中必須要有一個 private訪問級別的建構函式,這樣才會保證單例不會被系統中其他程式碼內例項化,再就是instance 成員變數和getInstance()方法必須是靜態的.
單例模式實現方式簡單,並且可靠,但是無法對instance例項做延遲載入,如果單例的建立過程很慢,由於instance成員變數是靜態的,因此在JVM載入單例類時,單例物件就會被建立,如果此時,這個單例類在系統中還扮演其他角色,那麼在任何使用這個單例類的地方都會初始化這個單例變數,而不管是否會被用到,比如String工廠,用於建立一些字串;
public class Singleton { private Singleton() { System.out.println("Singleton 建立"); } private static Singleton instance = new Singleton(); private static Singleton getInsSingleton() { return instance; } public static void createString() { System.out.println("建立Sting 的 Singleton"); } }
當執行Singleton.createString任務時,程式輸出:
"Singleton 建立
建立Sting 的 Singleton"
大家可以看到,雖然此時沒有使用單列類,單它還是被建立了出來,為了解決這個問題,提高系統在相關函式呼叫的反應速度,我們需要引入延遲載入機制.
public class LazySingleton {
private LazySingleton() {
System.out.println("Singleton 建立");
}
private static LazySingleton instance = null;
private static synchronized LazySingleton getInsSingleton() {
if(instance == null)
instance = new LazySingleton();
return instance;
}
}
我們對靜態變數instance初始化賦值null,確保系統啟動沒有額外的負載,其次,在getInstance()工廠方法中,判斷當前單例是否存在,如果存在返回,不存在建立;而且getInstance()方法必須是同步,不然在多執行緒環境下會出現第一條執行緒建立是還未賦值 第二條執行緒可能判斷為null重新建立.
但是實現後我們發現在多執行緒環境中它的耗時遠遠大於第一個單例模式,接下來在對此進行改造
public class StaticSingleton {
private StaticSingleton() {
System.out.println("Singleton 建立");
}
private static class SingLetonHolder{
private static StaticSingleton instance = new StaticSingleton();
}
public static StaticSingleton getInstance() {
return SingLetonHolder.instance;
}
}
這個實現中,單例模式使用內部類來維護單例的例項,當StaticSingleton被載入時,其內部類並不會被初始化,可以確保StaticSingleton類被載入JVM時,不會初始化單例類,而getInstance()方法呼叫時才會載入SingLetonHolder,從而初始化instance.
同時由於例項的建立是在類載入時完成,所以對多執行緒友好,getInstance()方法不需要同步修飾,因此實現方法同時兼備以上倆種實現的優點.
其實還沒有完,因為java中還有一種特殊情況,那就是反射機制強行呼叫單例類中的私有構造,生成多個單例.序列化與反序列化也會破壞單例,這倆種方式的解決辦法後續更新!!!
期待ing!!!!