創建型模式
- 單例模式
- 工廠模式
- 建造者模式
- 原型模式
- 對象池模式
單例模式
單例模式(Singleton pattern)是最常用的設計模式,它具有易於理解、使用簡便等特點。有時候單例模式會過度使用或者在不合適的場景下使用,這樣造成弊大於利的後果。
單例模式,顧名思義,用來保證一個對象只能創建一個實例,此外,它還提供了對實例的全局訪問方法。
單例模式的實現很簡單,只需要由單個類組成。爲確保單利實例的唯一性,所有的單利構造器都需要被聲明爲私有的(private),再通過聲明靜態(static)方法實現全局訪問獲得該單例實例。
public class Singleton
{
private static Singleton instance;
private Singleton()
{
//TODO
}
public static Singleton getInstance()
{
if(null == instance){
instance = new Singleton();
}
return instance;
}
public vid doSomething()
{
//TODO
}
}
當我們在代碼中使用該單例對象的時候,調用方式如下:
Singleton.getInstance().doSomething();
1. 同步鎖單例模式
單例模式的實現很簡單且高效,但是在多線程中的應用卻不能這樣隨意,如果實例爲空,那麼就會有出現兩個或者多個線程同時調用getInstance()的情況。這就會出現實例化多個對象的情況出現。
解決辦法很簡單,我們只需要創建一個代碼塊來檢查實例是否空線程安全。
- 向getInstance方法的聲明中添加synchronized關鍵字來保證其線程安全:
public static synchronized Singleton getInstance(){
//TODO
}
- 用synchronized代碼塊包裝 if( instance == null ) 條件。在這一環境中使用synchronized代碼塊時,需要制定一個對象來提供鎖,Singleton.class對象就起這種作用。
synchronized (Singleton.class){
if(instance == null){
instance = new Singleton();
}
}
2. 擁有雙重校驗鎖機制的同步鎖單例模式
上一個實現方式可以保證線程安全,但同時帶來了延遲。用來檢查實例是否被創建的代碼塊是線程同步的,也就是這個代碼塊同一時刻只能被一個線程執行,但是同步鎖(locking)只有在實例沒有被創建的情況下才起作用,如果單例實例已經被創建了,那麼任何線程都希望能夠用非同步的方式獲取當前的實例。
只有在單例模式爲實例化的情況下,才能在synchronized代碼塊前添加附加條件移動線程安全鎖:
if(instance == null){
synchronized(Singleton.class){
if(instance == null){
instance = new Singleton();
}
}
}
這是個很聰明的校驗方式,注意到instance==null條件被檢查了兩次,因爲我們需要保證synchronized代碼塊中也要進行一次檢查
3. 無鎖的線程安全單例模式
如何不通過鎖來使得單例模式線程安全呢?
Java中單例模式的最佳實踐中,類只會加載一次,通過聲明時直接實例化靜態成員的方式來保證一個類只有一個實例。這種實現方式避免了使用同步鎖和判斷實力是否被創建的額外檢查:
public class LockFreeSingleton{
private static final LockFreeSingleton instance = new LockFreeSingleton();
private LockFreeSingleton(){
//TODO
}
//這裏的synchronized的意義在哪裏呢?《設計模式與實踐》書中有synchronized,但是筆者暫時沒讀懂這個synchronized的意義
public static synchronized LockFreeSingleton getInstance(){
return instance;
}
public void doSomething(){
//TODO
}
}
4. 提前加載和延遲加載
上述方法,在早期版本的Java中被認爲是提前加載單例模式,但是在新版本的Java中,類只有在使用的時候纔會被加載,所以它算是一種延遲加載模式。此外,類加載的時機主要取決於JVM的實現機制,因而版本之間會有不同。所以進行設計的時候,要避免與JVM的實現機制進行綁定。
如果確實需要提前實例化,可以在程序的開始通過調用getInstance方法強制執行。
Singleton.getInstance();
參考(學習筆記來自於):
《Java設計模式與實踐》