如何設計乙個正確的單例模式類

2021-10-03 05:14:44 字數 1707 閱讀 7094

demo 1:

class

areturn m_instance;

}private

://建構函式和變數宣告為private,如果是基類希望被人繼承使用,則宣告為protecta(

);static a* m_instance;

}a* a::m_instance =

null

;

如上demo所示,這是大家習慣的正常建立單例類的方式。當他僅被使用於單執行緒,則完全沒問題。但如果用於多執行緒時,則可能會出現重複new物件的問題!

當多執行緒訪問「demo 1」中的單例時,此時獲取單例的函式為非執行緒安全的,所以,會導致多執行緒非同步執行時,出現重複new 物件的問題,這時可以為其加鎖的方式解決,如下demo 2所示:

demo 2:

class

a mt.

unlock()

;return m_instance;

}private

://建構函式和變數宣告為private,如果是基類希望被人繼承使用,則宣告為protecta(

);static a* m_instance;

}a* a::m_instance =

null

;

上述**中,相當於給獲取單例函式加了乙個函式全域性鎖,使該函式為執行緒安全函式。但如果是在高併發場景下,這個鎖的效能消耗是很大的!因為除了第一次真正建立例項外,其餘的操作都是「讀」操作,所以,需要對這個demo再進行改進。

根據「demo 2」中鎖描述的方式,則應該在第一次建立例項後,後續獲取例項時盡量不使用鎖,這樣就能解決高併發場景下鎖帶來的效能問題。實現方式如下所示:

demo 3:

class

a mt.

unlock()

;}return m_instance;

}private

://建構函式和變數宣告為private,如果是基類希望被人繼承使用,則宣告為protecta(

);static a* m_instance;

}a* a::m_instance =

null

;

如「demo 3」 所示,使用雙檢查鎖機制能有效的減少在高併發場景下因為鎖帶來的效能消耗,但是由於多執行緒在作業系統指令級別處理時,有可能會產生與**的順序不一致的問題,即new物件首先分配一段記憶體,然後返回位址,然後再初始化,這時就會導致其他執行緒拿到了乙個沒有初始化的物件而產生後續的一些問題,這就是「memory reorder」現象,詳情參考「所以,使用「demo 3」版本的雙檢查鎖是執行緒不安全的,大家不要去使用!!

更新後的demo如下圖所示:

demo 3:

classa}

return m_instance;

}private

://建構函式和變數宣告為private,如果是基類希望被人繼承使用,則宣告為protecta(

);static std::atomic> m_instance;

static std;

:mutex m_mt;

}std::atomic> a::m_instance =

null

;std::mutex a::m_mt;

如何設計乙個單例模式

單例類最簡單的c 實現 class single single static single getinstance return m pinstance single single m pinstance null 單例要求 參考 劍指offer c 保證執行緒安全 class single ret...

乙個工具類的單例模式

incompatible pointer types assigning to id from class 最後,發現,用單例模式才可以。原因 類方法的self不能充當delegate 下面是stackoverflow裡解決方法,構造單例模式 utility.h inte ce utility ns...

設計乙個簡單的單例設計模式

概念 單例模式 singleton pattern 涉及乙個單一的類,確保只有單個物件被建立。這個類提供一種訪問其唯一物件的方式,可以直接訪問,不需要例項化該類的物件。注意 1 單例類只能有乙個例項。2 單例類必須自己建立自己的唯一例項。3 單例類必須給所有其他物件提供這一例項。1.餓漢式 餓漢式是...