单例模式
什么是单例模式
有时候我们会有这样的需求,需要一个类只能有一个对象被实例化,这时我们可以使用单例模式。
单例模式通过类本身来管理其唯一实例,在设计这个类的时候,让它只能创建一个实例并提供对此实例的全局访问。因此单例模式有两个基本的条件:(1)确保一个类只有一个实例被创建 (2)提供一个对实例的全局访问指针
常见的单例模式的实现
常用的单例模式实现方法有两种:饿汉模式和懒汉模式
懒汉式单例模式:
在懒汉模式下,直到用户第一次调用GetInstance()方法时才new出对象的实例,而之后再调用GetInstance()方法时,只会返回第一次创建出来的对象的地址,不会再去创建实例,这样就保证了一个类只有一个实例,并且提供了全局访问的指针。
但是上面的代码却是存在内存泄漏和线程安全的问题的:
(1)首先是new出来的内存没有被释放,这个问题解决方法如下:
可以在内部声明一个内部类,用来管理实例的销毁。因为在程序运行过程中,系统会销毁所有的全局变量,所以系统会调用CSingleton的静态成员_CGarbo的析构函数,该析构函数会删除单例的唯一实例。
(2)在多线程下上面的代码还存在线程安全的问题,所以我们可以对它做同步的改进:
上面的代码加上锁之后已经能解决线程安全的问题了,但是这个锁有可能带来性能问题。
因为只有在第一次调用GetInstance()之前才存在线程安全问题,因为这时牵扯到内存的分配,但是在以后调用GetInstance()的时候就不会存在线程安全的问题了,在以后调用中,如果再去申请锁的话会带来性能问题,尤其当该函数调用多次的时候。
这时候就会有人提出来了用“双重判断”这种方法来解决性能的问题:
饿汉模式的单例:
在饿汉模式下,类的唯一实例是在类创建的时候就被创建出来,因为这时候GetInstance()方法内部有一个静态的类的实例。每次调用GetInstance()方法的时候就会返回这个静态变量的地址,而且不存在内存泄漏和线程安全的问题,所以推荐使用饿汉单例模式。