23種設計模式之單例模式
阿新 • • 發佈:2018-05-16
所有 存在 ins 結果 我們 程序 排序 volatil 計算機
單例模式(保證java程序中某個類只有一個實例存在)
單例模式有以下的特點:
- 單例類只能有一個實例
- 單例類必須自己創建自己的唯一的實類
- 單例類必須給其他所有對象提供這一實例
在計算機系統中,線程池,緩存,日誌對象,打印機,對話框常常被設計成單例對象。選擇單例模式就是為了避免不一致狀態。
一、懶漢式
public class Singleton{ private Singleton singleton = null;
private Singleton(){} private static Singleton getSingleton(){ if(singleton = null){ singleton = new Singleton(); } return singleton; } }
Singleton通過將構造器私有化,避免了在類外實例化,Singleton的實例只能通過getSingleton()方法訪問(不考慮反射)。
以上的懶漢式的代碼是沒有考慮線程安全的,可以通過以下三種方式將代碼進行改造
1.在getSingleton()方法上添加同步(同步是需要開銷的,正常執行的代碼我們不需要同步,只需要在對象初始化的時候同步)
private static synchronized Singleton getSingleton(){ if(singleton = null){ singleton = new Singleton(); }
}
2.雙重檢查鎖定(double-checked locking)
public static Singleton getInstance() { if (instance == null) { synchronized (Singleton.class) { if (instance == null) { instance = new Singleton(); } } }return instance; }
雙重檢查鎖定存在一個問題,這個問題是由指令重排序引起的。指令重排序是為了優化指令,提高程序運行效率,包括編譯器重排序和運行時重排序,指令重排序可以在不影響單線程程序執行結果的前提下進行。例如:instance = new Singleton();可以分解為以下偽代碼:
memory = allocate();//1.分配對象的內存空間 ctorInstance(memory);//2.初始化對象 instance = memory;//3.instance指向剛才分配的內存空間
經過指令重排序後:
memory = allocate();//1.分配對象的內存空間 instance = memory;//3.instance指向剛才分配的內存空間 ctorInstance(memory);//2.初始化對象
將第2步和第三部調換順序後,對於單線程的執行結果是沒有影響的,但是對於多線程就不一樣了。線程A執行了instance = memory(這對另外一個線程B是可見的),線程B這個時候通過 if(instance == null)判斷instance不為空,隨機返回,這個時候拿到的是未被完全初始化的實例,在使用的時候會有風險,這就是雙重檢查鎖定存在的問題。
在jdk1.5之後可以使用volatile禁止指令重排序:
public class Singleton { private static volatile Singleton instance; private Singleton() { } public static Singleton getInstance() { if (instance == null) { synchronized (Singleton.class) { if (instance == null) { instance = new Singleton(); } } } return instance; } }
3.靜態內部類(占位類)
public class Singleton { private static class InstanceHolder { public static Singleton instance = new Singleton(); } private Singleton() { } public static Singleton getInstance() { return InstanceHolder.instance; } }
二、餓漢式
public class Singleton{ private Singleton singleton = new Singleton(); private Singleton(){} private Singleton getInstance(){ return singleton; } }
23種設計模式之單例模式