乙個類只允許建立唯一乙個物件(或者例項),那這個類就是乙個單例類,這種設計模式就叫作單例設計模式,簡稱單例模式。
經典的設計模式有 23 種, 如果隨便抓乙個程式設計師,讓他說一說最熟悉的 3 種設計模式,那其中肯定會包含今天要講的單例模式,
單例模式主要用來確保某個型別的例項只能有乙個。比如手機上的藍芽之類的只能有乙個的例項的場景可以考慮用單例模式。
主要作用:
單例模式的實現,通常需要私有化構造方法,防止外部類直接使用單例類的構造方法建立物件
public class singleton
public static singleton getinstance()
return _instance;}}
這種方式比較簡單,但是不是執行緒安全的,多執行緒高併發情況下可能會導致建立多個例項,但是如果你的業務場景允許建立多個,我覺得問題也不大,如果一定要保證只能建立乙個例項,可以參考下面的做法
///
/// 雙重判空加鎖,飽漢模式(懶漢式),用到的時候再去例項化
///
public class singleton
public static singleton getinstance()}}
return _instance;}}
這種方式的執行過程會先檢查是否完成了例項化,如果已經例項化則直接返回例項,如果沒有就嘗試獲取鎖,獲得鎖之後再判斷一下是否已經例項化,如果已經例項化則返回例項,如果沒有就進行例項化
///
/// 餓漢模式-就是屌絲,擔心餓死。類載入就給準備好
///
public sealed class singleton1
public static singleton1 getinstance() => instance;
}
這也是一種常見的實現單例模式的用法,但是這種方式就不支援懶載入了,不像上面那種方式可以做到需要的時候再例項化,適用於這個物件會被頻繁使用或者這個模擬較小,是否例項化沒有什麼影響。
這個是之前忘記在**看到的微軟框架裡的一段**,類似,可能和原始碼並不完全一樣,只是提供一種實現思路
///
/// 使用 concurrentdictionary 實現的單例方法,用到的時候再去例項化
/// 這種方式類似於第一種方式,只是使用了併發集合代替了雙重判斷和 lock
///
public class singleton2
public static singleton2 getinstance() => instances.getoradd(1, k => new singleton2());
}
c# 裡提供了lazy
的方式實現延遲例項化
///
/// 使用 lazy 實現的單例方法,用到的時候再去例項化
///
public class singleton3
public static singleton3 getinstance() => lazyinstance.value;
}
驗證是否執行緒安全,驗證示例**:
console.writeline($"singleton");
enumerable.range(1, 10).select(i => task.run(() =>
");})).whenall().wait();
console.writeline($"singleton1");
enumerable.range(1, 10).select(i => task.run(() =>
");})).whenall().wait();
console.writeline($"singleton2");
enumerable.range(1, 10).select(i => task.run(() =>
");})).whenall().wait();
console.writeline($"singleton3");
enumerable.range(1, 10).select(i => task.run(() =>
");})).whenall().wait();
上面的whenall
是乙個擴充套件方法,就是呼叫的task.whenall
,輸出示例:
基於依賴注入框架,你可以不必擔心物件的建立和銷毀,讓依賴注入框架管理物件,這樣這個要實現單例模式的型別可以和其他普通型別一樣,只需要使用依賴注入框架註冊服務的時候指定服務生命週期為單例即可,比如使用微軟的依賴注入框架的時候可以使用services.addsingleton();
來註冊單例服務
關於使用雙檢鎖實現單例的時候是否要使用volatile
的問題,在 c# 如果你使用了lock
就沒有必要再去用volatile
標記要同步的物件了,
volatile
的主要是用在於解決多個cpu上執行的多個執行緒可以並且將快取資料和指令重新排序的問題。
如果它不是volatile
的,並且cpu a遞增了乙個值,則cpu b可能直到一段時間後才能真正看到該遞增的值,這可能會引起問題。如果它是volatile
的,則僅確保兩個cpu同時看到相同的資料。它根本不會阻止他們交錯讀取和寫入操作,而這正是您要避免的問題。
使用lock
也可以防止上述多cpu重新排序問題,所以使用了lock
就可以不需要再volatile
了
寫乙個高併發下面的單例模式 單例模式詳解
保證整個系統中乙個類只有乙個物件的例項,實現這種功能的方式就叫單例模式。1 單例模式節省公共資源 比如 大家都要喝水,但是沒必要每人家裡都打一口井是吧,通常的做法是整個村里打乙個井就夠了,大家都從這個井裡面打水喝。對應到我們計算機裡面,像日誌管理 印表機 資料庫連線池 應用配置。2 單例模式方便控制...
寫乙個高併發下面的單例模式 go語言併發之鎖的基操
go語言除了使用goroutine和channel這種csp模型,也支援傳統的併發模型,今天我們就說一下go中的鎖的使用。互斥鎖是傳統併發對共享的資源進行訪問空值的主要手段,在 sync 包中,mutex 結構體表示。該結構體具備兩個公共的方法,lock和unlock,前者鎖定當前的互斥量,後者是解...
Python 寫乙個單例模式
class amimal object a none b true def new cls,args,kwargs if not cls.a cls.a object.new cls 呼叫基類的 new 方法建立物件,修改類屬性 a return cls.a def init self,name,a...