一、何為單例設計模式 單例模式,顧名思義就是單個實例,程式中某個類只有一個實例存在。通常實在需要共用某個資源避免資源損耗的情況下使用到的。 二、單例設計模式的代碼實現 一說到單例模式的概念,我們首先會想到下麵的這種的寫法 把構造器設置為private方法,只有在類內部的方法中才能調用,外部無法進行調 ...
一、何為單例設計模式
單例模式,顧名思義就是單個實例,程式中某個類只有一個實例存在。通常實在需要共用某個資源避免資源損耗的情況下使用到的。
二、單例設計模式的代碼實現
一說到單例模式的概念,我們首先會想到下麵的這種的寫法
public class SingleInstance { private static SingleInstance singleInstance; private SingleInstance(){ } /** * 單例模式 * @return */ public static SingleInstance getSingleInstance(){ if(singleInstance == null){ singleInstance = new SingleInstance(); } return singleInstance; } }
把構造器設置為private方法,只有在類內部的方法中才能調用,外部無法進行調用創建實例。
的確這種寫法是最簡單的寫法,但是如果是在多線程的環境下會出現什麼樣的情況呢,假設有兩個線程同時進入這個獲取實例方法運行到 singleInstance == null的時候都會判斷這個條件為真,這時候兩個線程都會去創建對象實例,就會導致創建多個實例對象。面對這種情況我們首先想到的是將方法設置為同步方法便可以防止多個線程同時創建多個對象實例的情況。
同步方法單例模式:
public class SingleInstance { private static SingleInstance singleInstance; private SingleInstance(){ } /** * 單例模式 * @return */ public synchronized static SingleInstance getSingleInstance() { if (singleInstance == null) { singleInstance = new SingleInstance(); } return singleInstance; } }
是的,這種方法已經能解決多個線程下創建多個對象實例的問題,在併發不大的的情況下這種寫法是已經夠用的,那讓我們想想在併發量大的程式中,這樣的程式會出現什麼問題呢?假設有多個線程都需要獲取這個對象實例,因為這個方法是同步的,所以多個線程就會排隊進行執行,這樣子就會造成線程方法執行的阻塞。這種情況可以通過同步塊來解決。
同步方法塊的單例模式寫法(懶漢式):
public class SingleInstance { private static SingleInstance singleInstance; private SingleInstance(){ } /** * 單例模式 * @return */ public synchronized SingleInstance getSingleInstance(){ if(singleInstance == null){ singleInstance = new SingleInstance(); } return singleInstance; } }
這種單例模式的寫法就是現在最通用的寫法,在剛開始初始化時如果多個線程進入到方法需要創建對象,運行到synchronized (SingleInstance.class) 時就會進入排隊同步執行,當第一個線程運行到if(singleInstance == null)這句時,判斷為真就會執行創建代碼,創建實例對象。之後排隊的線程運行if(singleInstance == null)都是假的,因此就再不會創建對象。而之後的其他線程進入到方法時,在同步方法塊外層的if(singleInstance == null)判斷中就已經為假,因此便不會進入到同步方法塊中創建對象,會直接返回對象,而不用進行排隊,線程便不會進入到阻塞中。
當然我們還可以採用靜態變數初始化的方法來實現單例模式。
靜態的單例模式(餓漢式)
public class SingleInstance { private volatile static SingleInstance staticSingle = new SingleInstance(); private SingleInstance(){ } public static SingleInstance getStaticSingle(){ return staticSingle; } }
volatile關鍵字能夠確保當staticSingle變數對應的對象被創建時多個線程能夠及時地感知到。
採用這種方法,很簡單,但是這種情況下程式啟動初始化便要去創建對象,如果要創建的對象耗費記憶體很大,就會導致程式啟動時變得很慢,而且程式一啟動就會使記憶體處於使用較高的狀態。
單例設計模式是我們在程式中常見的一種設計模式,通過最簡單的寫法再到完美的單例模式的寫法,可以看出一個簡單的單例模式中也是蘊含許多原理在裡面。