單例模式
單例模式的概念
單例模式是一種對象創建型模式,使用單例模式,可以保證為一個類只生成唯一的實例對象。也就是說,在整個程序空間中,該類只存在一個實例對象。
GoF 對單例模式的定義是:保證一個類、只有一個實例存在,同時提供能對該實例加以訪問的全局訪問方法。
為什么適用單例模式
在應用系統開發中,我們常常有以下需求:
- 在多個線程之間,比如初始化一次 socket 資源;比如 servlet 環境,共享同一個資源或者 操作同一個對象
- 在整個程序空間使用全局變量,共享資源
- 大規模系統中,為了性能的考慮,需要節省對象的創建時間等等。
實現單例步驟常用步驟
- 構造函數私有化
- 提供一個全局的靜態方法(全局訪問點)
- 在類中定義一個靜態指針,指向本類的變量的靜態變量指針
懶漢式實現
如果單例對象構造十分耗時或者占用很多資源,比如加載插件啊, 初始化網絡連接啊,讀取文件啊等等,而有可能該對象程序運行時不會用到,那么也要在程序一開始就進行初始化,就會導致程序啟動時非常的緩慢。 所以這種情況使用懶漢模式(延遲加載)更好。
//懶漢式,需要才創建
class Singleton_lazy{
private:Singleton_lazy(){}//防拷貝Singleton_lazy(Singleton const&);Singleton_lazy & operator=(Singleton const&);
public:static Singleton_lazy *getInstace() //提供方法獲取{if(nullptr == pSingleton) //其它線程看到指針不為空,說明已創建,直接用,不需要再等待{m_mtx.lock(); //加鎖保證線程安全if (pSingleton == NULL){pSingleton = new Singleton_lazy;//new有可能失敗,拋出異常造成死鎖}m_mtx.unlock();return pSingleton;}}//內嵌垃圾回收類 RAII的思想class Garbo{~Garbo(){if (pSingleton != NULL){delete pSingleton;}}};
private:static Singleton_lazy * pSingleton;//類外初始化好static mutex m_mtx; //互斥鎖
};
//類外初始化
volatile Singleton_lazy * Singleton_lazy::pSingleton = NULL;
Singleton_lazy ::CGarbo Garbo;
mutex Singleton::m_mtx;
編譯器有可能進行優化:指令的重排
可以加上volatile
本來的順序
- 申請空間
- 構造對象
- 賦值
優化的順序
- 申請空間
- 賦值
- 構造對象
餓漢式實現
就是說不管你將來用不用,程序啟動時就創建一個唯一的實例對象。
//餓漢式,比較著急class Singleton_hungry{private:Singleton_hungry(){}//防止拷貝Singleton_hungry(Singleton const&);Singleton_hungry& operator=(Singleton const&);public:static Singleton_hungry *getInstace(){return pSingleton;}//實現內嵌垃圾回收類#if 0class Garbo{~Garbo(){if (pSingleton != NULL){delete pSingleton;}}};#endifprivate:static Singleton_hungry * pSingleton;};Singleton_hungry * Singleton_hungry::pSingleton = new Singleton_hungry;
線程安全
- 餓漢式是線程安全的,在main函數前創建對象
- 懶漢式不是線程安全的