設計模式:單例設計模式
阿新 • • 發佈:2019-01-25
內部 建議 null 需要 餓漢 重排序 let sin 網站
單例設計模式
由於某些類創建對象可能會耗費內存和花費時間。一般將這種類設計為單例設計模式會比較好。
1.對象在內存中只有一個,減少了內存的開銷
2.可以控制對象的創建時刻
單例模式的特點:
1.單例的類在整個JVM中只有一個實例
2.需要提供一個全局訪問點(1.公開的靜態變量,2.公開的靜態方法)
1.餓漢式:
特點:類加載的時候就創建了實例
//餓漢式 /* *1.類能被創建且只有一個實例 * 2.提供一個全局的訪問點 * */ public class Singleton { //創建唯一的實例對象 private static Singleton singletonInstance = newSingleton(); //修改默認的構造器為私有的,屏蔽外部的new方法 private Singleton() {} //全局的訪問點 public static Singleton getInstance() { return singletonInstance; } }
2.懶漢式
特點:在需要創建實例的時候才調用方法創建實例對象
class Singleton2 { //保存唯一的實例對象 private static Singleton2 singletonInstance; //修改默認的構造器為私有的,屏蔽外部的new方法private Singleton2() {} //全局的訪問點 public static Singleton2 getInstance() { if(singletonInstance == null) { singletonInstance = new Singleton2(); } return singletonInstance; } }
3.加鎖的懶漢式
由於一般懶漢式不能保證線程安全。所以需要在方法加鎖保證線程安全
//加鎖的懶漢式 class Singleton3 {//保存唯一的實例對象 private static Singleton3 singletonInstance; //修改默認的構造器為私有的,屏蔽外部的new方法 private Singleton3() {} //全局的訪問點 //給創建實例的方法加鎖。防止在多線程條件下線程問題 public synchronized static Singleton3 getInstance() { if(singletonInstance == null) { singletonInstance = new Singleton3(); } return singletonInstance; } }
4.雙重驗證的懶漢式
由於枷鎖的懶漢式對整個方法加了鎖,會導致每次調用創建實例方法都會需要進行等待,但是如果實例已經創建了,應該是不想繼續等待的。所以應該只在判斷實例是否創建的地方加鎖即可
class Singleton4 { //保存唯一的實例對象 private static Singleton4 singletonInstance; //修改默認的構造器為私有的,屏蔽外部的new方法 private Singleton4() {} //全局的訪問點 public static Singleton4 getInstance() { if(singletonInstance == null) { //獲取單例類的鎖 synchronized (Singleton4.class) { if(singletonInstance == null) { singletonInstance = new Singleton4(); } } } return singletonInstance; } }
5.加上volatile關鍵字防止重排序的雙重驗證懶漢式
創建一個對象可以分為3步:
雖然重排序不會影響單線程的執行結果,但是由於判斷的條件是instance == null,當分配了內存以後,其他線程來到判斷的地方,instance不為空,所以直接將引用指向實例對象。但是實例對象還沒有初始化,就會出現問題。
所以需要放防止重排序
class Singleton5 { //volatile防止重排序 private volatile static Singleton5 singletonInstance; //修改默認的構造器為私有的,屏蔽外部的new方法 private Singleton5() {} //全局的訪問點 //給創建實例的方法加鎖。防止在多線程條件下線程問題 public static Singleton5 getInstance() { if(singletonInstance == null) { //獲取單例類的鎖 synchronized (Singleton5.class) { if(singletonInstance == null) { singletonInstance = new Singleton5(); } } } return singletonInstance; } }
6.靜態內部類的方式:通過類加載過程的線程安全來保證創建單例實例的線程安全
class Singleton6 { //修改默認的構造器為私有的,屏蔽外部的new方法 private Singleton6() {} //靜態內部類保存唯一的實例對象 private static class InnerInstanceHolder{ private static Singleton6 singletonInstance = new Singleton6(); } //類加載是線程安全的,所以使用內部類持有唯一實例是線程安全的,且效率比較高 public static Singleton6 getInstance() { return InnerInstanceHolder.singletonInstance; } }
7.枚舉方式
//枚舉方式 public enum Singleton { INSTANCE; public void method() { } }
暫時還沒想懂枚舉方式的特點。列出參考網站下次研究:
為什麽我墻裂建議大家使用枚舉來實現單例
圖片參考來源:https://blog.csdn.net/qq_36109365/article/details/78090096
設計模式:單例設計模式