設計模式 最基礎也最重要的單例模式
阿新 • • 發佈:2021-09-09
設計模式 最基礎也最重要的單例模式
餓漢式單例
顧名思義 很餓很著急 會在程式執行一開始就吧類物件加載出來
所以有著可能浪費資源的缺點
簡單例子:
//餓漢式單例 public class Hungry { //可能會導致空間的浪費 private byte[] data=new byte[1024*1024]; //核心思想 構造器私有化 private Hungry(){ } private final static Hungry HUNGRY=new Hungry(); public static Hungry getInstance(){ return HUNGRY; } }
懶漢式單例
懶漢式單例的思想是 當需要用到我時才建立物件 但是簡單的寫法會在多執行緒出現問題
//懶漢式單例 public class LazyMan { private LazyMan(){ System.out.println(Thread.currentThread().getName()+"執行了建立方法"); } private static LazyMan lazyMan; public static LazyMan getInstance(){ if(lazyMan == null) { lazyMan = new LazyMan(); } return lazyMan; } public static void main(String[] args) { for(int i=0;i<10;i++){ new Thread(()->{LazyMan.getInstance();}).start(); } } }
執行結果可能會隨機出現多個執行緒建立了物件 不符合單例模式的思想
雙重鎖實現多執行緒懶漢實現
//懶漢式單例 public class LazyMan { private LazyMan(){ System.out.println(Thread.currentThread().getName()+"執行了建立方法"); } private static LazyMan lazyMan; public static LazyMan getInstance(){ //外層判斷主要是優化 使得不是每次都要獲取鎖 //雙重鎖懶漢式 稱為DCL懶漢 if(lazyMan==null){ synchronized (LazyMan.class){ if(lazyMan == null) { lazyMan = new LazyMan(); } } } return lazyMan; } public static void main(String[] args) { for(int i=0;i<10;i++){ new Thread(()->{LazyMan.getInstance();}).start(); } } }
通過鎖就可以實現只能一個執行緒獲取物件
但是實際上這樣在極端情況下也不是安全的 原因在與語句
lazyMan = new LazyMan();
底層是執行了很多步驟的 同時並不是原子操作
有可能出現第一個執行緒在建立物件 還沒完全建立完畢時 第二個執行緒判斷已經建立完畢 最後返回空物件
解決方法:
新增volatile
關鍵字
private volatile static LazyMan lazyMan;