1. 程式人生 > 實用技巧 >java之設計模式-單例模式

java之設計模式-單例模式

1.定義:指一個類只有一個例項,且該類能自行建立這個例項的一種模式。例如,Windows只能開啟一個工作管理員,這樣可以避免因開啟多個工作管理員視窗而造成記憶體資源的浪費,或出現各個視窗顯示內容不一致等錯誤。

例如:windows的回收站,作業系統中的檔案系統,多執行緒中的執行緒池,印表機的後臺處理服務,應用程式的日誌物件,資料庫的連線池,網站的計數器,web應用的配置物件,應用程式的對話方塊?

單例模式的特點:

a.單例類只有一個例項物件;

b.該單例物件必須由單例類自行建立;

c.單例類對外提供一個訪問該單例的全域性訪問點。

2.單例模式的結構與實現

  單例模式是設計模式中最簡單的模式之一,通常,普通類的建構函式是共公有的,外部類可以通過“new 建構函式()”來生成多個例項。但是,如果將類的建構函式設為私有的,外部類就無法呼叫該建構函式,也就無法生成多個例項。這時該類自身必須定義一個靜態私有例項,並向外提供一個靜態的共有函式用於建立或獲取該靜態私有例項。

2.1 單例模式的結構

  單例模式的主要角色如下:

2.2 單例模式的實現方式

步驟其實都是3步:

1.首先他不能被外部類例項化,所以構造方法必須用private關鍵字,第一步就是先寫一個私有的構造方法。

private Singleton(){ };

2.因為只能自己例項化自己,所以,要自己建立一個物件。以下哪個都可以,一個屬於懶漢式,一個屬於餓漢式。

private static Singleton instance; //懶漢式

private static HungrySingleton instance = new Singleton(); //餓漢式

3.要想外部訪問到這個物件,那麼必須定義一個public方法,這樣把自己建立的物件傳進去,讓外部類使用才可以。

public static Singleton getInstance()

  {return instance;}

第一種,懶漢:該模式的特點是因為比較懶,類載入時沒有生成單例,只有當第一次呼叫getInstance方法時才去建立這個單例。程式碼如下:

執行緒不安全的:因為沒有加鎖 synchronized,所以嚴格意義上它並不算單例模式。
這種方式 lazy loading 很明顯,不要求執行緒安全,在多執行緒不能正常工作。
public class LazySingleton { private LazySingleton(){ } private static
LazySingleton instance; public static LazySingleton getInstance(){ if(instance == null){ instance = new LazySingleton(); } return instance; } }
描述:這種方式具備很好的 lazy loading,能夠在多執行緒中很好的工作,但是,效率很低,99% 情況下不需要同步。
優點:第一次呼叫才初始化,避免記憶體浪費。
缺點:必須加鎖 synchronized 才能保證單例,但加鎖會影響效率。
getInstance() 的效能對應用程式不是很關鍵(該方法使用不太頻繁)。

public class Singleton {  
    private static Singleton instance;  
    private Singleton (){}  
    public static synchronized Singleton getInstance() {  
    if (instance == null) {  
        instance = new Singleton();  
    }  
    return instance;  
    }  
}

第二種,餓漢式:直接建立物件,不管你有沒有用,反正提前建立好了。就和怕餓著一樣,先準備好吃的再說。

public class HungrySingleton {
    private HungrySingleton(){
    }

    private static HungrySingleton instance = new HungrySingleton();

    public static HungrySingleton getInstance(){
        return instance;
    }
}

測試以上的是不是同一個物件:結果顯示物件地址都一樣,是同一個。

import org.testng.annotations.Test;

public class TestModel {
    @Test
    public  void test() {
        HungrySingleton hungrySingleton = HungrySingleton.getInstance();
        HungrySingleton hungrySingleton1 = HungrySingleton.getInstance();
        System.out.println(hungrySingleton);
        System.out.println(hungrySingleton1);
        System.out.println(hungrySingleton == hungrySingleton1);
        assert hungrySingleton == hungrySingleton1;

    }

    @Test
    public  void test1() {
        LazySingleton lazySingleton = LazySingleton.getInstance();
        LazySingleton lazySingleton1 = LazySingleton.getInstance();
        System.out.println(lazySingleton);
        System.out.println(lazySingleton1);
        System.out.println(lazySingleton == lazySingleton1);
        assert lazySingleton == lazySingleton1;

    }
}

第三種:雙檢鎖/雙重校驗鎖(DCL,即 double-checked locking)

描述:這種方式採用雙鎖機制,安全且在多執行緒情況下能保持高效能。
getInstance() 的效能對應用程式很關鍵。

public class Singleton {  
    private volatile static Singleton singleton;  
    private Singleton (){}  
    public static Singleton getSingleton() {  
    if (singleton == null) {  
        synchronized (Singleton.class) {  
        if (singleton == null) {  
            singleton = new Singleton();  
        }  
        }  
    }  
    return singleton;  
    }  
}

其他的參考:https://www.runoob.com/design-pattern/singleton-pattern.html