多線程的程序中,多個線程同時,注意是同時訪問Singleton類,調用GetInstance()方法,會有可能造成多個實例的。這個時候需要給進程加鎖來處理
Singleton類
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Singleton_Model
{
class Singleton
{
//私有化一個自己引用
private static Singleton instance;
//程序運行時候創建一個靜態只讀的進程輔助對象
private static readonly object syncRoot = new object();
//私有化構造器 杜絕了外界利用New實例化本類的可能
private Singleton()
{
}
//此方法是獲得本類實例的唯一全局訪問點
public static Singleton GetInstance()
{
lock (syncRoot)
{
if (instance == null)
{
instance = new Singleton();
}
}
return instance;
}
}
}
缺點:每次調用Instance都需要Lock會很耗費性能
新的Singleton類
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Singleton_Model
{
class Singleton
{
//私有化一個自己引用
private static Singleton instance;
//程序運行時候創建一個靜態只讀的進程輔助對象
private static readonly object syncRoot = new object();
//私有化構造器 杜絕了外界利用New實例化本類的可能
private Singleton()
{
}
//此方法是獲得本類實例的唯一全局訪問點
public static Singleton GetInstance()
{
if (instance==null)
{
lock (syncRoot)
{
if (instance == null)
{
instance = new Singleton();
}
}
}
return instance;
}
}
}
這裏可以看到裏外兩層判斷!沒錯這裏沒有問題 !當Instance爲null並且同時有兩個線程調用GetInstance方法時,它們都將可以通過第一重的Instancenull的判斷,然後由於Lock機制,這兩個線程則只能有一個進入 另一個排隊等候。此時若是沒有第二重的Instancenull的判斷,則第一個線程創建了實例,而第二個線程還是可以繼續再創建新的實例,這樣就沒有達到單例的目的!!
靜態初始化:其實在實際的應用當中,C#與公共語言運行庫也提供了一種‘靜態初始化’的方法,這種方法不需要開發人員顯示的編寫線程安全的代碼,即可以解決多線程環境下它不是安全的問題!實現更簡單,但是談不上更好!
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Singleton_Model
{
//sealed阻止發生派生,而派生可能會增加實例。
public sealed class Singleton1
{
private static readonly Singleton1 instance = new Singleton1();
private Singleton1()
{
}
public static Singleton1 GetInstance()
{
return instance;
}
/**
*
* * 這樣的實現與前面的實例類似,也是解決了單例模式試圖解決的兩個基本問題,全局訪問和實例化控制,
* 1 公共靜態屬性爲訪問實例提供了一個全局的訪問點。
* 不同之處在於它依賴公共語言運行庫來初始化變量。由於構造方法是私有的,因此不能再類本身以外實例化
* Singleton1類。因此 變量引用的是可以在系統中存在的唯一的實例。不過要注意,instance變量標記爲readonly
* 這意味着只能在靜態初始化期間或在類構造函數中分配【MSDN】。
* 由於這種靜態初始化的方式是在自己被加載時就將自己實例化 所以形象的稱爲餓【漢式單例模式】
* 原先的單例處理模式是要再第一次被引用時,纔會將自己實例化 所以被形象稱爲【懶漢單例模式】
* 【漢式單例模式】 靜態初始化方式,它是類一加載就實例化的對象,所以要提前佔用系統資源
* 【懶漢單例模式】 面臨着多線程訪問的安全問題 需要做雙重鎖定才能保證安全。
* 所以要用哪一種 必須考慮實際的需求 C#【漢式單例模式】基本能滿足需求
*/
}
}
這樣的實現與前面的實例類似,也是解決了單例模式試圖解決的兩個基本問題,全局訪問和實例化控制,
* 1 公共靜態屬性爲訪問實例提供了一個全局的訪問點。
* 不同之處在於它依賴公共語言運行庫來初始化變量。由於構造方法是私有的,因此不能再類本身以外實例化
* Singleton1類。因此 變量引用的是可以在系統中存在的唯一的實例。不過要注意,instance變量標記爲readonly
* 這意味着只能在靜態初始化期間或在類構造函數中分配【MSDN】。
* 由於這種靜態初始化的方式是在自己被加載時就將自己實例化 所以形象的稱爲餓【漢式單例模式】
* 原先的單例處理模式是要再第一次被引用時,纔會將自己實例化 所以被形象稱爲【懶漢單例模式】
* 【漢式單例模式】 靜態初始化方式,它是類一加載就實例化的對象,所以要提前佔用系統資源
* 【懶漢單例模式】 面臨着多線程訪問的安全問題 需要做雙重鎖定才能保證安全。
* 所以要用哪一種 必須考慮實際的需求 C#【漢式單例模式】基本能滿足需求