单例模式
什么是单例模式?
保证整个系统中一个类只有一个对象的实例,实现这种功能的方式就叫单例模式。
①单例模式是保证系统实例唯一性的重要手段。单例模式首先通过将类的实例化方法私有化来防止程序通过其他方式创建该类的实例,然后通过提供一个全局唯一
获取该类实例的方法帮助用户获取类的实例,用户只需也只能通过调用该方法获取类的实例。
②单例模式的设计保证了一个类在整个系统中同一时刻只有一个实例存在,主要被用于一个全局类的对象在多个地方被使用并且对象的状态是全局变化的场景下。
同时单例模式为系统资源的优化提供了很好的思路,频繁创建或销毁对象都会增加系统的资源消耗,而单例模式保障了整个系统只有一个对象能被使用,很好地节
约了资源。
饿汉式:线程安全,没有加锁执行效率高,但类加载时就创建了实例,可能浪费内存资源。
懒汉式:线程不安全,在使用时才创建实例,可以通过双重锁机制保证线程安全,或使用静态内部类优化效率。
为什么饿汉模式是安全的?
类加载的方式是按需加载,且只加载一次。
饿汉模式的对象只在类加载的时候被实例化,再加上,由于一个类在整个生命周期中只会被加载一次,因此该单例类只会创建一个实例,
也就是说,线程每次都只能也必定只可以拿到这个唯一的对象。因此就说,饿汉式单例天生就是线程安全的。
懒汉模式的对象是通过new操作处理的,多个线程同时new的时候就有可能线程不安全
为什么要用单例模式?
1、单例模式节省公共资源
比如:大家都要喝水,但是没必要每人家里都打一口井是吧,通常的做法是整个村里打一个井就够了,大家都从这个井里面打水喝。
对应到我们计算机里面,像日志管理、打印机、数据库连接池、应用配置。
2、单例模式方便控制
就像日志管理,如果多个人同时来写日志,你一笔我一笔那整个日志文件都乱七八糟,如果想要控制日志的正确性,那么必须要对关键的代码进行上锁,只能一个一个按照顺序来写,而单例模式只有一个人来向日志里写入信息方便控制,避免了这种多人干扰的问题出现。
实现单例模式的思路
1. 构造私有:
如果要保证一个类不能多次被实例化,那么我肯定要阻止对象被new 出来,所以需要把类的所有构造方法私有化。
2.以静态方法返回实例。
因为外界就不能通过new来获得对象,所以我们要通过提供类的方法来让外界获取对象实例。
3.确保对象实例只有一个。
只对类进行一次实例化,以后都直接获取第一次实例化的对象。
单例模式的思路
意图:保证一个类仅有一个实例,并提供一个访问它的全局访问点。
主要解决:一个全局使用的类频繁地创建与销毁。
何时使用:当您想控制实例数目,节省系统资源的时候。
如何解决:判断系统是否已经有这个单例,如果有则返回,如果没有则创建。
关键代码:构造函数是私有的。
应用实例:
1、Windows 是多进程多线程的,在操作一个文件的时候,就不可避免地出现多个进程或线程同时操作一个文件的现象,所以所有文件的处理必须通过唯一的实例来进行。
2、一些设备管理器常常设计为单例模式,比如一个电脑有两台打印机,在输出的时候就要处理不能两台打印机打印同一个文件。
优点:
1、在内存里只有一个实例,减少了内存的开销,尤其是频繁的创建和销毁实例(比如管理学院首页页面缓存)。
2、避免对资源的多重占用(比如写文件操作)。
缺点:没有接口,不能继承,与单一职责原则冲突,一个类应该只关心内部逻辑,而不关心外面怎么样来实例化。
使用场景: 1、要求生产唯一序列号。 2、WEB 中的计数器,不用每次刷新都在数据库里加一次,用单例先缓存起来。 3、创建的一个对象需要消耗的资源过多,比如 I/O 与数据库的连接等。
注意事项:getInstance() 方法中需要使用同步锁 synchronized (Singleton.class) 防止多线程同时进入造成 instance 被多次实例化。
单例模式的实现(懒汉式+饿汉式)
一、饿汉模式的意思是,我先把对象(面包)创建好,等我要用(吃)的直接直接来拿就行了。
#include<iostream> #include<string> #include<string.h> #include<map> using namespace std; //饿汉式-空间换时间--线程安全 class Singleton { public: //提供对外获取实例的接口 static Singleton *getInstance() { static Singleton instance; return &instance; } private: //构造私有 Singleton() {}; //析构 ~Singleton() {}; }; //类外初始化类内的静态成员变量 //<静态成员数据类型> <类名>::静态成员变量名=初始化值 int main() { Singleton * s = Singleton::getInstance(); system("pause"); return 0; }
二、因为饿汉模式可能会造成资源浪费的问题,所以就有了懒汉模式,懒汉模式的意思是,我先不创建类的对象实例,等你需要的时候我再创建。
#include<iostream> #include<string> #include<string.h> #include<map> using namespace std; //懒汉式-时间换空间-延迟较高---多线程下不安全,需要在new的时候加锁 class Singleton { public: //提供对外获取实例的接口 static Singleton *getInstance() { if (instance == nullptr) { instance = new Singleton(); } return instance; } private: //构造私有 Singleton() {}; //析构 ~Singleton() {}; //静态成员函数只能访问类内的静态成员函数和静态成员数据 static Singleton *instance; }; //类外初始化类内的静态成员变量 //<静态成员数据类型> <类名>::静态成员变量名=初始化值 Singleton * Singleton::instance = nullptr; int main() { Singleton * s = Singleton::getInstance(); system("pause"); return 0; }