單例模式,英文名為:Singleton pattern。首先,我們先去理解字面意思。Singleton:一個,獨身。pattern:模式,圖案,樣品。在字面上,可以理解為“一個樣品”。哈哈。再來看看特點:
- 只能有一個執行個體
- 必須自己建立自己唯一執行個體
- 必須給所有其他的對象提供這一執行個體
看到了這些特點,你在想,那麼有了這些特點有什麼作用、又有什麼好處呢。很好,對待這些不明白、沒見過的知識點抱有種種疑問是非常好的節奏。
單例模式的作用簡單點理解是為了避免不一致狀態,避免政出多頭。單例模式為一個物件導向的應用程式提供了對象惟一的訪問點,不管它實現何種功能,整個應用程式都會同享一個執行個體對象。
在電腦系統中,線程池、緩衝、日誌對象、對話方塊、印表機、顯卡的驅動程式對象常被設計成單例。這些應用都或多或少具有資源管理員的功能。每台電腦可以有若干個印表機,但只能有一個Printer Spooler,以避免兩個列印工作同時輸出到印表機中。每台電腦可以有若干通訊連接埠,系統應當集中管理這些通訊連接埠,以避免一個通訊連接埠同時被兩個請求同時調用。
下面通過代碼來瞭解下單例模式中的懶漢式和餓漢式。
懶漢式一:
public class Singleton{//私人的預設構造子private Singleton(){}//注意,這裡沒有finalprivate static Singleton single=null;//靜態Factory 方法public synchronized static Singleton getInstance(){ if(single==null) { single=new Singleton(); } return single; }}
懶漢式二:
public class Singleton{ private Singleton mInstance = null; private Singleton() { } public static Singleton getInstance() { if (mInstance == null) { synchronized (Singleton.class) { if (mInstance == null) { mInstance = new Singleton(); } } } return mInstance; }}
在“懶漢式一”中,將執行個體的構造方法私人化,使外部類不能通過new來構造出Singleton對象,只能通過Singleton類中提供的getInstance()方法來得到Singleton對象。當有多個線程調用getInstance()方法時,因為在方法調用上加了同步,所以雖然安全執行緒了,但是每次都要同步,會影響效能,畢竟大多的情況下是不需要同步的。
在“懶漢式二”中,在getInstance()方法中做了兩次null檢查,確保了只有第一次調用單例的時候才會做同步,這樣也是安全執行緒的,同時避免了每次都同步的效能損耗。
餓漢式:
public class Singleton{ private Singleton mInstance = new Singleton; private Singleton() { } public static Singleton getInstance() { return mInstance; }}
“餓漢式”在類建立的同時就已經建立好一個靜態對象供系統使用,以後不再改變,所以天生是安全執行緒的。
餓漢式在類建立的同時就執行個體化一個靜態對象出來,不管之後會不會使用這個單例,都會佔據一定的記憶體,但是相應的,在第一次調用時速度也會更快,因為其資源已經初始化完成。
而懶漢式顧名思義,會消極式載入,在第一次使用該單例的時候才會執行個體化對象出來,第一次調用時要做初始化,如果要做的工作比較多,效能上會有些延遲,之後就和餓漢式一樣了。
什麼是安全執行緒。
如果你的代碼所在的進程中有多個線程在同時運行,而這些線程可能會同時運行這段代碼。如果每次運行結果和單線程啟動並執行結果是一樣的,而且其他的變數的值也和預期的是一樣的,就是安全執行緒的。
或者說:一個類或者程式所提供的介面對於線程來說是原子操作,或者多個線程之間的切換不會導致該介面的執行結果存在二義性,也就是說我們不用考慮同步的問題,那就是安全執行緒的。
若每個線程中對全域變數、靜態變數只有讀操作,而無寫操作,一般來說,這個全域變數是安全執行緒的;若有多個線程同時執行寫操作,一般都需要考慮線程同步,否則的話就可能影響安全執行緒。
上述內容若有錯誤,望指出。