單例模式是一種設計模式.
單例模式表示在定義的某一個類中,只能有唯一的一個對象(即只能有一個實例).
優點:提高了封裝性,外部不能輕易的改變實例.
餓漢模式
含義:程序啓動後就會立即加載到內存.
缺點:啓動比較慢.
代碼如下:
#include <iostream>
using namespace std;
template<class T>
class Singleton
{
public:
static T* GetSingleton()
{
return &value;
}
private:
static T value;
};
template<class T>
T Singleton<T>::value = T();
int main()
{
Singleton<int>::GetSingleton();
return 0;
}
懶漢模式
含義:啓動的時候不加載,只有當使用的時候纔會加載到內存.
#include <iostream>
using namespace std;
//懶漢模式
template<class T> //類模板
class singleton
{
public:
static T* GetSingleton()
{
if(value == NULL)
{
value = new T();
}
return value;
}
private:
static T* value;
};
template<class T>
T* singleton<T>::value = NULL;
int main()
{
singleton<int>::GetSingleton();
return 0;
}
上面這個代碼存在一個很重要的問題:
1.如果在多線程的環境下,在函數GetSingleton()中如果進行判斷時如果同時多個線程頻繁的進行判斷,那麼就會存在線程安全問題,如果多個線程都判斷爲空那麼就會new出來很多對象,那麼明顯就是不安全的. 解決:加鎖,在判斷前進行加鎖,在出了if判斷再進行解鎖. 問題:如果有多個進程頻繁的獲取鎖,然後再進行判斷,然後再釋放.那麼效率就會下降,加鎖和解鎖也是一種消耗. 解決:在加鎖前再進行一次判斷,如果爲空才進行進行加鎖.這樣就會大大減少了加解鎖的消耗. |
具體的代碼如下:
template<class T>
class singleton
{
public:
static T* GetSingleton()
{
if(value == NULL) //這樣就只有爲空纔會進來進行加鎖解鎖(這樣就不會頻繁獲取鎖)
{
lock(); //這是一句僞代碼(加鎖)
//如果在這兒加鎖,所有的線程到這兒都會先加鎖(這也是一種消耗),再判斷,這樣就會造成效率低.所以在這兒之前再進行一次判斷
//但是在這兒加鎖也會滿足線程安全
if(value == NULL)
{
value = new T();
}
unlock(); //僞代碼(解鎖)
}
return value;
}
private:
static volatile T* value; //加上volatile爲了防止編譯器過度優化
};
template<class T>
volatile T* singleton<T>::value = NULL;