定义
- 类的实例只有一个
 
特点
- 构造函数私有化,在类内部只调用一次
 - 拷贝构造函数私有化或者禁用
 
饿汉单例
- 类加载的时候立刻进行实例化 
- 定义这个单例类的时候,就把这个静态的单例对象创建出来了
 
 
example
// 饿汉模式
class TaskQueue
{
public:// = delete 代表函数禁用, 也可以将其访问权限设置为私有TaskQueue(const TaskQueue& obj) = delete;TaskQueue& operator=(const TaskQueue& obj) = delete;static TaskQueue* getInstance(){return m_taskQ;}
private:TaskQueue() = default;static TaskQueue* m_taskQ;
};
// 静态成员初始化放到类外部处理
TaskQueue* TaskQueue::m_taskQ = new TaskQueue;int main()
{TaskQueue* obj = TaskQueue::getInstance();
}
 
懒汉单例
- 类加载的时候不去创建这个唯一的实例,而是在需要使用的时候再进行实例化
 
example
// 懒汉模式
class TaskQueue
{
public:// = delete 代表函数禁用, 也可以将其访问权限设置为私有TaskQueue(const TaskQueue& obj) = delete;TaskQueue& operator=(const TaskQueue& obj) = delete;static TaskQueue* getInstance(){if(m_taskQ == nullptr){m_taskQ = new TaskQueue;}return m_taskQ;}
private:TaskQueue() = default;static TaskQueue* m_taskQ;
};
TaskQueue* TaskQueue::m_taskQ = nullptr;
 
缺点
- 多线程环境下,可能生成多个单例 
- 在调用
getInstance()函数获取单例对象的时候,如果在单线程情况下是没有什么问题的,如果是多个线程,调用这个函数去访问单例对象就有问题了。假设有三个线程同时执行了getInstance()函数,在这个函数内部每个线程都会new出一个实例对象。此时,这个任务队列类的实例对象不是一个而是3个,很显然这与单例模式的定义是相悖的 
 - 在调用
 
解决方案
- 加锁
 - 局部静态变量
 
class TaskQueue
{
public:// = delete 代表函数禁用, 也可以将其访问权限设置为私有TaskQueue(const TaskQueue& obj) = delete;TaskQueue& operator=(const TaskQueue& obj) = delete;static TaskQueue* getInstance(){static TaskQueue taskQ;return &taskQ;}void print(){cout << "hello, world!!!" << endl;}private:TaskQueue() = default;
};int main()
{TaskQueue* queue = TaskQueue::getInstance();queue->print();return 0;
}
 
在程序的第 9、10 行定义了一个静态局部队列对象,并且将这个对象作为了唯一的单例实例。使用这种方式之所以是线程安全的,是因为在C++11标准中有如下规定,并且这个操作是在编译时由编译器保证的:
如果指令逻辑进入一个未被初始化的声明变量,所有并发执行应当等待该变量完成初始化。
PS:局部静态变量
- 在函数内部进行初始化,且只在第一次进入函数时执行初始化操作。初始化方式和普通局部变量类似,只是因为它是静态的,后续函数调用时不会再次初始化。
 
