設計模式之單例 Singleton 模式

2021-08-26 17:27:48 字數 2895 閱讀 7588

如果要保證系統在乙個類最多只能存在乙個例項時,我們就需要單例模式。這種情況在應用中經常碰到,例如快取池、資料庫連線池、執行緒池、一些應用服務例項等等。在多執行緒環境中。為了保證例項的唯一性其實並不簡單。

1、最簡單的單例模式

為了限制該類的物件被隨意的建立,需要保證該類構造方法是私有的,這樣外部類就無法建立該類的物件;另外,為了方便給客戶物件提供單例物件的使用,我們為提供乙個全域性訪問點,如下:

package com.pattern.singleton;

public class singleton

public static singleton getinstance()

}

singleton類中只有乙個構造方法,它是被private修飾的,客戶物件無法建立該物件的例項。

我們為此單例實現了乙個全域性訪問點 public static singleton getinstance()方法。

注意:instance 變數是私有的,外界無法訪問。此實現是執行緒安全的,當多個執行緒同時去訪問該類getinstance()方法時,不會初始化多個不同的物件,因為jvm在載入此類的時候,對於static資料的初始化只能由乙個執行緒執行且僅一次。

2、單例效能-延遲建立

如果出於效能方面的考慮,我們希望延遲例項化單例物件(static屬性在載入類時就會被初始化),只有在第一次使用該類的例項時才去例項化。此時我們就可以使用延遲建立,我們可以把單例的例項化過程移至getinstance()方法中,而不是在載入時預先建立。當訪問該方法時,首先判斷該例項物件是不是已經被例項化過了,如果已被初始化,則直接返回這個物件的引用;否則,建立這個例項並初始化,如下:

package com.pattern.singleton;

public class unthreadsafesingleton

return instance; }}

注意: if(instance == null) 判斷是否例項化完成了,該方法不是執行緒安全的。

2.1、執行緒安全

在高併發的環境中,getinstance()方法返回了多個指向不同的例項物件,原因如何呢?

thread1  

thread2

1 if(instance==null)

2 3 instance = new unthreadsafesingelton();

4 return instance;

5 6 1

2 if(instance==null)

3 4 instance = new unthreadsafesingelton();

5 return instance; 6

如果這兩個執行緒按照上述步驟執行,我們不難發現,在時刻1和2,由於還沒建立單例物件,thread1和thread2都會進入建立單例的**快分別建立例項。在時刻3 thread1建立了乙個例項物件,但是thread2此時無法知道,於是繼續建立乙個新的例項物件,導致這兩個執行緒持有的例項並非為同乙個。

更為糟糕的是,在沒有自動記憶體**機制的語言平台(c++)會因為我們認為建立了乙個單例物件,從而忽略了其他執行緒所產生的物件,不會手動去**他們,從而引起記憶體洩露。

為了解決此類問題,我們給方法新增 synchronized關鍵字,如下:

package com.pattern.singleton;

public class unthreadsafesingleton

return instance; }}

這樣,再多的執行緒訪問都只會例項化乙個單例物件。

3、double-check locking

雖然在多執行緒環境下是執行緒安全了,但是在多執行緒高併發的情況下,給次方法加上synchronized關鍵字會是的效能大不如前。synchronized關鍵字對整個getinstance()方法同步是沒有必要的:我們只要保證例項化這個物件的那段邏輯被乙個執行緒執行就可以了,而返回引用的那段**是沒有必要同步的。如下:

package com.pattern.singleton;

public class doublechecksingleton

}} return instance; }}

注意: 在getinstance()方法裡,首先判斷次例項是否被建立了,如果還沒有建立,首先使用synchronized同步例項化**塊。在同步**塊裡,還需要再次檢查是否已經建立了單例物件,因為:如果沒有第二次檢查,這是有兩個執行緒 thread a 和 thrad b 同時進入該方法,他們都檢測到instance 為null 不管那個執行緒先佔據了同步鎖,並建立了例項物件,都不會阻止另外乙個執行緒進入例項**塊重新建立例項物件,這樣,同樣會生成兩個例項物件,所以,我們在同步的**塊中,要進行第二次判斷,判斷該物件是否被建立。

屬性instance是被volatile修飾的,因為volatile具有synchronized的可見性特點,也就是說執行緒能夠自動發現volatile變數的最新值。這樣,如果instance例項化成功,其他執行緒便能立刻發現。

4、initialization on demand holder

package com.pattern.singleton;

public class lazyloadedsingleton

private static class lazyholder

public static lazyloadedsingleton getinstance()

}

Swift設計模式之單例 SINGLETON

保證乙個類公有乙個例項,並提供乙個訪問它的全域性訪問點。1 使用場景 2 實現的重要三個步驟 swift語言不支援變數及方法的許可權,沒有辦法隱藏變數及方法,可以隨意直接建立乙個例項。單例的建立有很多寫法,swift支援只有struct支援靜態變數,class不支援靜態變數,所以很容易想到,在類的內...

java設計模式 單例模式(Singleton)

設計模式 design pattern 是一套被反覆使用 經過分類編目 設計經驗的總結。目的 為了可重用 讓 更容易被他人理解 保證 的可靠性。適用場景 有些物件我們只需要乙個,比如,配置檔案 工具類 執行緒池 快取 日誌物件等。作用 保證整個應用程式中某個例項有且只有乙個。餓漢式 public c...

23種設計模式之單例模式 Singleton

singleton是軟體開發中最常用的的設計模式之一,它有三個要點 只能有乙個例項 構造器私有化 在內部自行建立該例項 用乙個靜態變數來儲存唯一的例項 向外部提供獲得例項的方式 1.直接暴露 2.用靜態變數的get方法獲取 兩種寫法 public class singleton public cla...