單例模式:一種創建型設計模式, 讓你能夠保證一個類只有一個實例, 並提供一個訪問該實例的全局節點。
方法為私有化構造函數,在類中定義靜態實例(先new為餓漢 后new為懶漢)
在方法定義靜態方法,返回唯一實例
下面介紹三種單例模式java代碼寫法
1。懶漢式(需要用時再申請)缺點:有線程不安全風險
(2021/1/18更新:為什么不安全呢?
競態條件的類型“先檢查后執行”的一種情況——延遲初始化
假設有線程A B同時執行這個方法,A看到是null的,取決於時序、線程調度方式,如果B同樣需要看到是null的(未初始化完成),則會出現覆蓋)
class lhan { private int address = 1999; private static lhan instance; //私有化構造函數 外部只能用實例調用 無法新聲明新實例 private lhan() { } void put(int k) { address = k; return; } int get() { return address; } //返回唯一實例 public static lhan getInstance() { if (instance == null) { instance = new lhan(); } return instance; } }
2.餓漢式(不管是否調用 先申請) 優點:線程安全。 缺點:如果不調用的話浪費內存
class ehan{ private int age=20; private ehan(){};//私有化構造函數 private static ehan instance=new ehan(); void put(int k) { age = k; return; } public int get() { return age; } public static ehan getInstance() { return instance; } }
3.雙檢鎖式(綜合了餓漢 懶漢的優點 並改正了其缺點)
這樣既保證了線程安全,又比直接上鎖提高了執行效率,還節省了內存空間。
class DoubleCheack{ private static DoubleCheack instance; private int age=1; private DoubleCheack(){}; void put(int k) { age = k; return; } public int get() { return age; } public static DoubleCheack getInstance() { if(instance==null) {//先判斷是否為null 后上鎖進行初始化 synchronized (DoubleCheack.class) { if (instance == null)//將對象上鎖之后再次判斷 是否有別的線程初始化了 instance = new DoubleCheack(); } } return instance; } }
主函數測試用例(雙檢鎖)
無論對於幾個實例內數據如何變動 都指向一個唯一實例(instance)
參考博文:
https://blog.csdn.net/absolute_chen/article/details/93380566