日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

单例模式 Singleton

發(fā)布時間:2025/6/17 编程问答 37 豆豆
生活随笔 收集整理的這篇文章主要介紹了 单例模式 Singleton 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

單例模式簡介

單例模式是面向?qū)ο蟪绦蛟O(shè)計中比較常用的設(shè)計模式,一個類在程序的整個生命周期中只能產(chǎn)生不超過一個對象。(注意:這里為什么說不超過一個對象,而不是有且只有一個對象。在使用懶漢式單例模式下,如果這個單例模式的類一直沒有使用的話,這個類就不會產(chǎn)生對象,即0個對象。如果使用了這個類,不管有多少處使用,這個類也只能產(chǎn)生1個對象。當然了,還有題外話:假如不使用這個類的話,為啥要設(shè)計這個類呢?)

單例模式的要點有三個

1.這個類只能有一個實例;

2.這個類必須自行創(chuàng)建這個實例;

3.這個類必須自行向整個系統(tǒng)提供這個實例。

對于單利模式的要點,在單例模式的實現(xiàn)角度,包括下列三點

1.為了防止使用者通過new操作(類的默認構(gòu)造函數(shù)),賦值操作(類的默認重載賦值運算符)生成多個實例,這個類的默認構(gòu)造函數(shù),默認的重載賦值運算符必須設(shè)置為私有的;

2.類中定義一個私有的該類的對象,類必須自行創(chuàng)建這個唯一的對象并自己保存;

3.類中需要提供一個公共的靜態(tài)函數(shù),能夠給使用者獲取到類自己保存的這個唯一對象,從而能夠獲取到這個類提供的其他真正提供具體服務(wù)的方法。

常見的兩種實現(xiàn)方式

1.餓漢方式

在類被加載的時候,就直接初始化一個該類的對象。后面不管這個類有沒有被使用,對象都一直存在。

2.懶漢方式

在類真正在使用的時候,才會初始化一個該類的對象。在沒有使用這個類之前,這個對象都不在。

?

c++實現(xiàn)

1.餓漢方式

靜態(tài)對象版本示例代碼

頭文件

1 #ifndef __SINGLETON_H__ 2 #define __SINGLETON_H__ 3 4 class CMySingleton 5 { 6 public: 7 //提供一個獲取該實例的方法 8 static CMySingleton& getInstance(); 9 //真正提供服務(wù)的具體方法 10 void invoke1(); 11 12 private: 13 //防止通過默認構(gòu)造函數(shù)創(chuàng)建新對象 14 CMySingleton(); 15 //默認析構(gòu)函數(shù) 16 ~CMySingleton(); 17 //防止通過拷貝構(gòu)造函數(shù)和賦值運算符創(chuàng)建新對象 18 CMySingleton(const CMySingleton&); 19 CMySingleton& operator=(const CMySingleton&); 20 private: 21 static CMySingleton m_pInstance; 22 }; 23 24 #endif // !__SINGLETON_H__

?

實現(xiàn)文件

1 #include "singleton.h" 2 #include <iostream> 3 4 CMySingleton CMySingleton::m_pInstance;//static 成員需要類外定義 5 6 CMySingleton::CMySingleton() 7 { 8 } 9 10 CMySingleton::~CMySingleton() 11 { 12 } 13 14 CMySingleton& CMySingleton::getInstance() 15 { 16 return m_pInstance; 17 } 18 19 void CMySingleton::invoke1() 20 { 21 std::cout << "call invoke1" << std::endl; 22 }

?

測試文件

1 #include "singleton.h" 2 #include <iostream> 3 4 using namespace std; 5 6 int main() 7 { 8 //調(diào)用單例類的具體方法 9 CMySingleton::getInstance().invoke1(); 10 11 return 0; 12 }

?

靜態(tài)指針版本示例代碼:

頭文件

1 #ifndef __SINGLETON_H__ 2 #define __SINGLETON_H__ 3 4 class CMySingleton 5 { 6 public: 7 //提供一個獲取該實例的方法 8 static CMySingleton* getInstance(); 9 //真正提供服務(wù)的具體方法 10 void invoke1(); 11 12 private: 13 //防止通過默認構(gòu)造函數(shù)創(chuàng)建新對象 14 CMySingleton(); 15 //默認析構(gòu)函數(shù) 16 ~CMySingleton(); 17 private: 18 static CMySingleton* m_pInstance; 19 }; 20 21 #endif // !__SINGLETON_H__

?

實現(xiàn)文件

1 #include "singleton.h" 2 #include <iostream> 3 4 CMySingleton* CMySingleton::m_pInstance = new CMySingleton();//static 成員需要類外定義,直接創(chuàng)建靜態(tài)指針對象 5 6 CMySingleton::CMySingleton() 7 { 8 } 9 10 CMySingleton::~CMySingleton() 11 { 12 if (m_pInstance) 13 { 14 delete m_pInstance; 15 m_pInstance = nullptr; 16 } 17 } 18 19 CMySingleton* CMySingleton::getInstance() 20 { 21 return m_pInstance; 22 } 23 24 void CMySingleton::invoke1() 25 { 26 std::cout << "call invoke1" << std::endl; 27 }

?

測試文件

1 #include "singleton.h" 2 #include <iostream> 3 4 using namespace std; 5 6 int main() 7 { 8 //調(diào)用單例類的具體方法 9 CMySingleton::getInstance()->invoke1(); 10 11 return 0; 12 }

運行結(jié)果

個人理解:靜態(tài)指針版本不需要把聲明私有的拷貝構(gòu)造函數(shù)和重載賦值運算符,因為對與這兩種操作,在指針的操作后最終拿到的還是同一個對象的地址。

?

2.懶漢方式

單例類的對象在真正使用的時候才去創(chuàng)建,簡單的實現(xiàn)如下

頭文件

1 #ifndef __SINGLETON_H__ 2 #define __SINGLETON_H__ 3 4 #include <iostream> 5 6 class CMySingleton 7 { 8 public: 9 //提供一個獲取該實例的方法 10 static CMySingleton* getInstance(); 11 //真正提供服務(wù)的具體方法 12 void invoke1() 13 { 14 std::cout << "call invoke1" << std::endl; 15 } 16 17 private: 18 //防止通過默認構(gòu)造函數(shù)創(chuàng)建新對象 19 CMySingleton() 20 //默認析構(gòu)函數(shù) 21 ~CMySingleton() 22 private: 23 static CMySingleton* m_pInstance; 24 }; 25 26 #endif // !__SINGLETON_H__

實現(xiàn)文件

1 #include "singleton.h" 2 #include <iostream> 3 4 CMySingleton* CMySingleton::m_pInstance = nullptr;//static 成員需要類外定義,定義的時候不創(chuàng)建對象,在真正使用的時候才創(chuàng)建 5 6 CMySingleton::CMySingleton() 7 { 8 } 9 10 CMySingleton::~CMySingleton() 11 { 12 if (m_pInstance) 13 { 14 delete m_pInstance; 15 m_pInstance = nullptr; 16 } 17 } 18 19 CMySingleton* CMySingleton::getInstance() 20 { 21 if (m_pInstance == nullptr) 22 { 23 m_pInstance = new CMySingleton(); 24 } 25 return m_pInstance; 26 } 27 28 void CMySingleton::invoke1() 29 { 30 std::cout << "call invoke1" << std::endl; 31 }

?

測試文件

1 #include "singleton.h" 2 #include <iostream> 3 4 using namespace std; 5 6 int main() 7 { 8 //調(diào)用單例類的具體方法 9 CMySingleton::getInstance()->invoke1(); 10 11 return 0; 12 }

?運行結(jié)果與餓漢式一樣。

在單線程情況下運行程序執(zhí)行沒有問題,但是在多線程環(huán)境下,在未創(chuàng)建實例的時候如果同時有多個進程請求這個類的服務(wù),由于m_pInstance == nullptr為True,將會導(dǎo)致同時創(chuàng)建多個實例。因此在創(chuàng)建實例的時候加鎖判斷實例是否已經(jīng)創(chuàng)建,如果未創(chuàng)建才需要new。

?

3.改進的懶漢方式

頭文件

1 #ifndef __SINGLETON_H__ 2 #define __SINGLETON_H__ 3 4 #include <iostream> 5 #include <pthread.h> 6 7 class CMySingleton 8 { 9 public: 10 //提供一個獲取該實例的方法 11 static CMySingleton* getInstance(); 12 //真正提供服務(wù)的具體方法 13 void invoke1() 14 { 15 std::cout << "call invoke1" << std::endl; 16 } 17 18 private: 19 //防止通過默認構(gòu)造函數(shù)創(chuàng)建新對象 20 CMySingleton(); 21 //默認析構(gòu)函數(shù) 22 ~CMySingleton(); 23 private: 24 static CMySingleton* m_pInstance; 25 static pthread_mutex_t m_mutex; 26 }; 27 28 class AutoLock 29 { 30 public: 31 AutoLock(pthread_mutex_t* mutex): m_mutex(mutex) 32 { 33 pthread_mutex_lock(m_mutex); 34 } 35 ~AutoLock() 36 { 37 pthread_mutex_unlock(m_mutex); 38 } 39 40 private: 41 pthread_mutex_t* m_mutex; 42 43 }; 44 45 #endif // !__SINGLETON_H__

此處使用了pthread的互斥量來作鎖操作,同時定義了一個AutoLock的類用來加鎖(此類不是必須,只要在實現(xiàn)里面能夠在判斷前正確加鎖即可)。

實現(xiàn)文件

1 #include "singleton.h" 2 #include <pthread.h> 3 4 CMySingleton* CMySingleton::m_pInstance = nullptr;//static 成員需要類外定義,定義的時候不創(chuàng)建對象,在真正使用的時候才創(chuàng)建 5 pthread_mutex_t CMySingleton::m_mutex = PTHREAD_MUTEX_INITIALIZER; 6 7 CMySingleton::CMySingleton() 8 { 9 } 10 11 CMySingleton::~CMySingleton() 12 { 13 pthread_mutex_destroy(&m_mutex); 14 if (m_pInstance) 15 { 16 delete m_pInstance; 17 m_pInstance = nullptr; 18 } 19 } 20 21 CMySingleton* CMySingleton::getInstance() 22 { 23 AutoLock lock(&m_mutex); 24 if (m_pInstance == nullptr) 25 { 26 m_pInstance = new CMySingleton(); 27 } 28 return m_pInstance; 29 }

測試文件和測試結(jié)果跟上面一樣。

此時,由于判斷對象是否存在前已經(jīng)加鎖了,因此多線程情況下也能正常執(zhí)行了。

但是引入了另外一個問題,每次在客戶端的線程(或者進程)調(diào)用的時候都要加鎖,導(dǎo)致效率不高。為了解決這個問題,下面對這個實現(xiàn)進行改進。

?

4.進一步改進的懶漢方式

頭文件不變,測試文件不變,實現(xiàn)文件如下

#include "singleton.h"CMySingleton* CMySingleton::m_pInstance = nullptr;//static 成員需要類外定義,定義的時候不創(chuàng)建對象,在真正使用的時候才創(chuàng)建 pthread_mutex_t CMySingleton::m_mutex = PTHREAD_MUTEX_INITIALIZER;CMySingleton::CMySingleton() { }CMySingleton::~CMySingleton() {pthread_mutex_destroy(&m_mutex);if (m_pInstance){delete m_pInstance;m_pInstance = nullptr;} }CMySingleton* CMySingleton::getInstance() {if (m_pInstance == nullptr){AutoLock lock(&m_mutex);if (m_pInstance == nullptr){m_pInstance = new CMySingleton();}}return m_pInstance; }

此處在加鎖前多一次判斷實例是否存在(雙重判定),因此,在第一次即使多個線程(或者進程)進來的時候第一次判斷都是空,此時多個線程調(diào)用都會競爭鎖資源,獲取到說資源的調(diào)用會創(chuàng)建第一個實例并返回后,之前競爭鎖資源的線程或者進程再判斷,實例已經(jīng)創(chuàng)建,因此不會再重新new。第一波的處理可以比較完美的解決了。

后續(xù)繼續(xù)有客戶端的請求進來,由于再第一層判斷實例已經(jīng)存在,即m_pInstance != nullptr,因此也不會進入if語句中執(zhí)行加鎖操作,直接就把現(xiàn)有的實例返回了,從而后續(xù)的請求也能比較完美的解決了。

綜上所述,使用雙重判定的懶漢方式僅會在沒有生成對象的第一波請求的時候才會效率較低,后續(xù)所有的請求由于都不存在加鎖等操作,效率也能提上來了。

?

轉(zhuǎn)載于:https://www.cnblogs.com/huangwenhao/p/11132678.html

總結(jié)

以上是生活随笔為你收集整理的单例模式 Singleton的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。