java設計模式之單例模式5種方法及優缺點小結
阿新 • • 發佈:2019-01-06
單例設計模式的用處。
單例設計模式是指,某個類只有一個例項。在計算機系統中類似於印表機和最常見的就是工作管理員的對話方塊,不管幾個使用者同時登入windows 開啟的任務對話方塊只有一個。
常見的幾種實現方式:
1.lazy-load
/* 適合單執行緒模式 延遲載入 lazy-load*/
public class Singleton {
/* 私有的靜態物件變數,來標記是否初始化過 也用來把例項化進行快取*/
private static Singleton instance = null;
/* 私有的建構函式防止外部呼叫 */
private Singleton (){}
/* 供外部呼叫的介面是public的其餘均為private */
public static Singleton getInstance(){
/* 單執行緒模式先如果物件變數為空,那麼需要建立 */
/* 但是多執行緒下這個地方需要同步,否則會出現兩個執行緒都建立了一個例項的情況 */
if(instance == null){
instance = new Singleton();
}
return instance;
}
}
2.lazy-load的變種1執行緒安全了但是效率很差
/* 多執行緒下可以使用但是如果兩個執行緒同時想建立例項的化,加鎖和等待鎖是很耗時的
如果不想建立例項了但是還要獲取鎖,這樣很不好。 lazy-load */
public class Singleton{
private static Singleton instance = null;
private Singleton(){
}
public static synchronized Singleton getInstance(){
if(instance == null){
instance = new Singleton();
}
return instance;
}
}
3,lazy-load的變種2執行緒安全了,效率有提高
/* 對上一種方式進行了優化,提前判斷一下變數是否為空,前後兩次判斷是否存在 lazy-load */
/* 但是這種兩次if判斷的存在出錯的情況 */
/* */
public class Singleton{
/* 此處使用volatile關鍵字 */
private volatile static Singleton instance = null;
private Singleton(){}
public static Singleton getInstance(){
/* 第一次判斷 隔絕在已經例項之後呼叫get介面獲取例項物件的情況,放置這些情況仍然呼叫鎖 */
if(instance == null){
/* 防止兩個執行緒同時進行建立例項 */
synchronized(Singleton.class){
/* 這個if判斷也是必須的,如果出現了兩個執行緒同時等待鎖,但是第一個執行緒釋放之後,第二個執行緒進入但是卻沒有判斷鎖是否釋放的化,那麼仍然是建立了兩次,同時這個instance也一定是volatile 的保證可見性 */
if(instance == null){
instance = new Singleton();
}
}
}
return instance;
}
}
但是這樣的doubleif仍然有問題。雖然使用了volatile 雖然兩次if判斷。
因為無序寫入:
這個double if 判斷的參考了這個寫的特別好,值得學習
引申:
4.餓漢式
/* 餓漢式,類載入就會建立例項而不去管你用不用, 但是記憶體使用率低 執行緒安全。因為虛擬機器保證了類只會載入一次,在裝載類的時候是不會併發的 */
public class Singleton{
private static Singleton instance = new Singleton();
private Singleton(){}
public static Singleton getInstance(){
return instance;
}
}
5.靜態內部類
/* 靜態內部類 */
/* 由於內部類不會在載入外部類的時候進行載入,那麼這個也屬於lazy-load。但是這種延遲載入的載入也是class的載入jvm保證只有一次所以同樣執行緒安全 */
public class Singleton{
private Singleton(){}
private static class SingletonIneerClass{
private final static Singleton instance = new Singleton();
}
public static Singleton getInstance(){
return SingletonIneerClass.instance();
}
}