單例模式SingleTon

2021-08-17 01:31:50 字數 4553 閱讀 5231

乙個類只生成乙個物件(確保某乙個類只有乙個例項,而且自行例項化並向整個系統提供這個例項)

通過定義乙個private的建構函式,避免被其他類new出來乙個物件,不可以被例項化

1.單例模式的懶載入(第一次執行到此處,載入到記憶體)

class singleton

}};static singleton* mysingleton::mysingleton = mysingleton();

2.單例模式的快載入(還沒有使用就載入)

class singletonb

mutex_unlock();

}return mysingleton;

};singletonb* mysingletonb::mysingleton = null;

pthread_mutex_t singletonb::mutex;

之前面試被問到乙個問題,為什麼要使用單例模式而不使用全域性變數呢?兩者又有什麼區別呢?

當時想到的不是很多,於是後期整理了一下

單例模式和全域性變數區別:

單例模式的優點

1)由於單例模式在記憶體中只有乙個例項,減少了記憶體開支,特別是乙個物件需要頻繁地建立、銷毀時,而且建立或銷毀時效能又無法優化。

2)由於只生成乙個例項,減少了系統的效能開銷,當乙個物件的產生需要比較多的資源時,如讀取配置、產生其他依賴物件時,則可以通過在應用啟動時直接產生乙個單例物件,然後用永久駐留記憶體的方式解決。

3)可以避免對資源的多重占用,例如乙個寫檔案動作,由於只有乙個例項存在中,避免對同乙個資源檔案的同時寫操作。

4)單例模式可以在系統設定全域性的訪問點,優化和共享資源訪問。例如可以設計乙個單例類,負責所有資料表的對映處理。

單例模式的缺點:

1)單例模式一般沒有介面,擴充套件很困難。因為單例模式要求」自行例項化」,並且提供單一例項、介面或抽象類是不可能被例項化。特殊情況下可以實現介面、被繼承等,需要在系統開發中根據環境判斷。

2)單例模式對測試是不利的。在並行環境中,如果單例模式沒有完成,是不能進行測試的,沒有介面也不是使用mock的方式虛擬乙個物件。

3)單例模式與單一職責原則有衝突。乙個類應該只實現乙個邏輯,而不關心他是否是單例模式,是不是單例取決於環境。

使用場景

在乙個系統中,要求乙個類有且僅有乙個物件,如果出現多個物件就會出現「不良反應」,

具體場景如下:

1)要求生成唯一序列號的環境;

2)在整個專案中需要乙個共享訪問點或共享資料,例如乙個web頁面上的計數器,可以不用把每次重新整理都記錄到資料庫中,使用單例模式儲存計數器的值,並確保是執行緒安全的。

3)建立乙個物件需要消耗的資源過多,如要訪問io和資料庫等資源;

4)需要定義大量的靜態常量和靜態方法的環境,可以是單例模式(或者宣告為static)

注意事項:

在高併發情況下,需要注意單例模式的執行緒同步問題。

如果讓我們設計乙個類,只能生成該類的乙個例項,我們需要把建構函式設為私有函式以禁止他人創

建例項。可以定義乙個靜態的例項,在需要的時候建立該例項。

public

sealed

class singleton1

private

static singleton1 instance = null;

public

static singleton1 instance}}

此次**實現在singleton1的靜態屬性instance中,只有在instance為null時才建立乙個例項,以避免重複建立。同時把建構函式定義為私有函式,可以確保只建立乙個例項。

但是,這只適用於單執行緒環境,在多執行緒的情況下就會產生問題。設想如果兩個執行緒同時執行到判斷instance是否為null的if條件語句,並且此時instance沒有建立時,那麼兩個執行緒都會建立乙個例項,此時singleton1就不再滿足單例模式的要求了。

在《劍指offer》中,看到了可以在多執行緒下進行工作的單例模式。

為了保證在多執行緒下只能得到型別的乙個例項,需要加上乙個同步鎖。

public

sealed

class singleton2

private

static

readonly

object syncobj = new

object();

private

static singleton2 instance = null;

public

static singleton2 instance

return instance;}}

}

我們還是假設有兩個執行緒同時向建立乙個例項。由於在乙個時刻只有乙個執行緒能得到同步鎖,當第

乙個執行緒加上鎖,第二個執行緒只能等待。當第乙個執行緒發現例項還沒有建立時,會建立乙個例項。接

著第乙個執行緒釋放同步鎖,此時第二個執行緒可以加上同步鎖並執行接下來的**。

這時候由於例項已經被第乙個執行緒建立出來,第二個執行緒就不會重複建立例項,保證了多執行緒下只得

到乙個例項。

但是,每次通過屬性instance得到例項,都會試圖加上乙個同步鎖,而加鎖是乙個非常耗時的操作,在沒有必要的時候我們應該去避免加鎖。

可行的解法:加同步鎖前後兩次判斷例項是否存在

我們只是在例項沒有建立之前需要加鎖操作,以保證只有乙個執行緒建立出例項。而當例項已經建立之後,我們已經不需要再做枷鎖操作了。

public

sealed

class singleton3

private

static

object syncobj = new

object();

private

static singleton3 instance = null;

public

static single3 instance

}return instance;}}

}

singleton3只有當instance為null即沒有建立時,需要加鎖操作。當instance已經建立,則無需進行加鎖。這樣下來相對於singleton2,效率好很多。

還有一種解法,利用靜態建構函式

這裡利用到了c#種乙個語法特性(ps;本人對c#不是特別了解,也是從書中學到的一種)。

c#語法中有乙個函式能確保只呼叫依次,那就是靜態建構函式。

實現如下:

public

sealed

class singleton4

private

static singleton4 instance = new singleton4();

public

static singleton4 instance}}

由於c#是在呼叫靜態建構函式時初始化靜態變數,.net執行時能夠確保只呼叫依次靜態建構函式,保證了只初始化一次instance。.net 執行時發現第一次使用乙個型別時會自動呼叫該型別的靜態建構函式。因此,在singleton4中,例項instance會在第一次用到singleton4時會被建立。

但是,這個實現單例模式方式,仍然會過早地建立例項,從而降低記憶體的使用效率

接下來還有非常不錯的解法:實現按需建立例項

public

sealed

class singleton5

public

static single singleton5 instance

}class nested /*類預設私有*/

internal

static

readonly singleton5 instance = new singleton5();}}

在singleton5中,在內部定義乙個私有型別nested。當第一次用到這個巢狀型別時,會呼叫靜態建構函式建立singleton5的例項instance。

型別nested只在屬性singleton5.instance中被用到,由於其私有屬性他人無法使用nested型別。因此當我們第一次試圖通過屬性singleton5.instance得到singleton5的例項時,會自動呼叫nested的靜態建構函式建立例項instance。

當然,如果不呼叫屬性singleton5.instance,也就不會觸發.net執行時呼叫nested,也不會建立例項,真正做到了按需建立。

上述提到的這些方法中,

Singleton 單例 模式

singleton 模式的宗旨在於確保某個類只有乙個例項,別且為之提供乙個全域性訪問點。為了防止其他工作人員例項化我們的類,可以為該類建立唯一乙個構造器,並將構造器的可見 設定為私有。值得注意的是,如果我們建立了其他的非私有的構造器,或者根本沒有為該類提 供構造器,那麼其他人員還是能例項化我們的類。...

Singleton 單例 模式

今天看了,單例模式。感覺他的本質就是,控制類例項的個數。特例就是,控制static變數的唯一性,保證各個程式共享著同一例項。乙個例子 package singleton description 這是乙個單例模式的使用demo author kyle goal 實現乙個類僅有乙個例項 singleto...

單例(Singleton)模式

單例模式的特點 singleton模式包含的角色只有乙個,那就是singleton。singleton擁有乙個私有建構函式,確保使用者無法通過new取得singleton的例項。除此之外,該模式中包含乙個靜態私有成員變數instance與靜態公有方法instance。instance方法負責檢驗並例...