设计模式的理解:单例模式(Singleton)
單例模式使用的目的是 ①一個類只能初始化出一個對象?②保證對象是線程安全的。
其做法:
1、將 構(gòu)造函數(shù) 和拷貝構(gòu)造函數(shù) 設(shè)置為私有 并將自身類的指針設(shè)置成靜態(tài)成員,其函數(shù)方法也設(shè)置成靜態(tài)方法。保證該類只創(chuàng)建一個對象
2、通過加鎖的方式,對 對象訪問加以限制
class Singleton { private:static Singleton * instance; Singleton (){} Singleton(const Singleton& other);public:static Singleton* getInstance() { if (instance == nullptr) { instance = new Singleton(); } return instance; } }以上在單線程中是可以滿足一個類對象只會被初始化一次的條件。但是在多線程中 假如其中一個線程在執(zhí)行? ?instance = new Singleton();? ?語句前,而另外一個剛好進入 if 語句時,這個類就會被初始化兩次。所以上述的編碼方式時線程不安全的。
二、雙重加鎖
class Singleton { private:static Singleton * instance; Singleton (){} Singleton(const Singleton& other);public:static Singleton* getInstance() { if (instance == nullptr) { Lock lock;if(instance == nullptr){instance = new Singleton(); }} return instance; } }上述代碼是雙重鎖機制,當(dāng)一個線程先獲取到鎖的時候,第二個線程讀鎖時就會等待第一個鎖初始化完對象后才繼續(xù)執(zhí)行。但是上述寫法沒有考慮到內(nèi)存讀寫reorder不安全。
正常創(chuàng)建對象實例會走三步驟
1) 分配對象內(nèi)存
2) 調(diào)用構(gòu)造器,執(zhí)行初始化
3) 將對象的引用賦值給變量。
然而在編譯器優(yōu)化等問題下,在實際可能的運行順序是,先執(zhí)行第三步再執(zhí)行第二部,即先引用給對象再調(diào)用構(gòu)造器。
如果
假如其中一個線程在執(zhí)行? ?instance = new Singleton();? ?語句時,分配完了內(nèi)存,將對象將對象的引用賦值給變量,此時第二個線程判斷 if (instance == nullptr) 不成立直接返回了一個還未初始化完的對象。那么就會造成線程不安全。這個創(chuàng)建對象的二三步驟亂序執(zhí)行實際上叫重排序。
在JAVA ,C#中 ,新增了一個關(guān)鍵字volatile,在聲明成員變量時??volatile static Singleton instance;? ? 表示禁止?instance創(chuàng)建對象時重排序。
而在C++ 11版本的跨平臺實現(xiàn)
//C++ 11版本之后的跨平臺實現(xiàn) // atomic c++11中提供的原子操作 std::atomic<Singleton*> Singleton::m_instance; std::mutex Singleton::m_mutex;/* * std::atomic_thread_fence(std::memory_order_acquire); * std::atomic_thread_fence(std::memory_order_release); * 這兩句話可以保證他們之間的語句不會發(fā)生亂序執(zhí)行。 */ Singleton* Singleton::getInstance() {Singleton* tmp = m_instance.load(std::memory_order_relaxed);std::atomic_thread_fence(std::memory_order_acquire);//獲取內(nèi)存fenceif (tmp == nullptr) {std::lock_guard<std::mutex> lock(m_mutex);tmp = m_instance.load(std::memory_order_relaxed);if (tmp == nullptr) {tmp = new Singleton;std::atomic_thread_fence(std::memory_order_release);//釋放內(nèi)存fencem_instance.store(tmp, std::memory_order_relaxed);}}return tmp; }?
或者有更簡潔的C++寫法,但在C++11版本前不支持。
class Singleton{ public:// 注意返回的是引用。static Singleton& getInstance(){static Singleton m_instance; //局部靜態(tài)變量return m_instance;} private:Singleton(); //私有構(gòu)造函數(shù),不允許使用者自己生成對象Singleton(const Singleton& other); };?
?
?
?
?
?
總結(jié)
以上是生活随笔為你收集整理的设计模式的理解:单例模式(Singleton)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 设计模式的理解:构造器模式(Builde
- 下一篇: 设计模式的理解:享元模式 (Flywei