單例模式:保證一個類僅有一個實例,并提供一個訪問它的全局訪問點。
單例模式分為懶漢式和餓漢式
懶漢式是當該實例第一次被引用時,才將自己實例化;
餓漢式是在被加載時就將自己實例化了。
懶漢式
class Singleton{
public:
static Singleton* getInstance();
void doSomething();
void destroy();
private:
Singleton();
~Singleton();
Singleton(const Singleton&);
Singleton& operator = (const Singleton&);
static Singleton* instance;
};
Singleton* Singleton::instance = NULL;
Singleton::Singleton() {}
Singleton::~Singleton() {}
Singleton* Singleton::getInstance() {
if(instance == NULL)
instance = new Singleton();
return instance;
}
void Singleton::destroy() {
delete this;
instance = NULL;
}
int main() {
Singleton::getInstance()->doSomething();
Singleton::getInstance()->destroy();
return 0;
}
懶漢式是線程不安全的,當單例模式應用在多線程中,應該使用鎖進行同步
class Singleton{
public:
static Singleton* getInstance();
void doSomething();
void destroy();
private:
Singleton();
~Singleton();
Singleton(const Singleton&);
Singleton& operator = (const Singleton&);
static Singleton* instance;
};
Singleton* Singleton::instance = NULL;
Singleton::Singleton() {}
Singleton::~Singleton() {}
Singleton* Singleton::getInstance() {
if(instance == NULL) {
lock();
if(instance == NULL)
instance = new Singleton();
unlock();
return instance;
}
void Singleton::destroy() {
delete this;
instance = NULL;
}
int main() {
Singleton::getInstance()->doSomething();
Singleton::getInstance()->destroy();
return 0;
}
而餓漢式是線程安全的
class Singleton{
public:
static Singleton* getInstance();
void doSomething();
void destroy();
private:
Singleton();
~Singleton();
Singleton(const Singleton&);
Singleton& operator = (const Singleton&);
static Singleton* instance;
};
Singleton* Singleton::instance = new Singleton();
Singleton::Singleton() {}
Singleton::~Singleton() {}
Singleton* Singleton::getInstance() {
return instance;
}
void Singleton::destroy() {
delete this;
instance = NULL;
}
int main() {
Singleton::getInstance()->doSomething();
Singleton::getInstance()->destroy();
return 0;
}
優缺點
餓漢式
優點
1. 線程安全
2. 在類加載的同時已經創建好一個靜態對象,調用時反應速度快
缺點
資源效率不高,可能getInstance()永遠不會執行到,但執行該類的其他靜態方法,那么這個實例仍然初始化
懶漢式
優點:
避免了餓漢式的那種在沒有用到的情況下創建事例,資源利用率高,不執行getInstance()就不會被實例,可以執行該類的其他靜態方法。
缺點:
不是線程安全,在多線程中需要線程同步,同步加鎖的過程提高了系統的開銷
應用場景
- 網站的計數器,一般也是采用單例模式實現,否則難以同步。
- 應用程序的日志應用,一般都何用單例模式實現,這一般是由于共享的日志文件一直處于打開狀態,因為只能有一個實例去操作,否則內容不好追加。
- Web應用的配置對象的讀取,一般也應用單例模式,這個是由于配置文件是共享的資源。
- 數據庫連接池的設計一般也是采用單例模式,因為數據庫連接是一種數據庫資源。數據庫軟件系統中使用數據庫連接池,主要是節省打開或者關閉數據庫連接所引起的效率損耗,這種效率上的損耗還是非常昂貴的,因為何用單例模式來維護,就可以大大降低這種損耗。
- 多線程的線程池的設計一般也是采用單例模式,這是由于線程池要方便對池中的線程進行控制。
- 操作系統的文件系統,也是大的單例模式實現的具體例子,一個操作系統只能有一個文件系統。