QT单例模式、多线程、双重校验加锁

   单例模式
   [定义]
    自己来判断是否已经实例化。保证一个类仅有一个实例,并提供一个访问它的全局访问点。

   [本质]
    ①定义私有的本类静态对象、对象指针或对象引用;
    ②将该类的构造函数设为private,防止外部用new来实例化它;
    ③外部仅能通过公有静态成员函数获得唯一对象。

   [步骤]:
    1、.h文件中声明:static Socket *getInstance();注意是声明在public类型下,这是本质③中的公有静态成员函数,用于供外部调用
    2、头文件中这样声明,那么就要有对应的.cpp文件中定义,定义的函数如下
    Socket *Socket::getInstance()//最基础的用法,简单粗暴有效,适用于单线程场景
    {
        static Socket instance; //局部静态变量,若定义为指针,则需要手动释放内容
        return &instance;
    }
    3、.h文件中private下声明构造函数设为private,防止外部用new来实例化它;(本demo中explicit Socket(QWidget *parent = nullptr);原先public改为private修饰)
    4、外部调用,本项目是mainwindow.cpp中通过m_Socket = Socket::getInstance();调用

   [应用场景]
    最基础的单例实现方式,用于一般场景,尤其是单线程场景就够用了;
    如果多线程中,这样做会出现两个线程同时new出这个单例类的唯一实例的情况发生;
    所以多线程场景中需要对此处进行双重校验检索

   [关于懒汉式和饿汉式的单例模式区分]
    懒汉式:当程序第一次访问单件模式实例时才进行创建
    ——如上就是懒汉模式,特点是在getInstance被调用时才新建Socket的对象instance
    所以在启动的时候,会感觉到比饿汉式略快,因为并没有做对象的实例化。 但是在第一次调用的时候,会进行实例化操作,感觉上就略慢。
    饿汉式:在程序启动或单件模式类被加载的时候,单件模式实例就已经被创建。
    ——就是如上的static Socket instance;放到getInstance函数外去声明定义(在类的.h文件中声明即可)
    如上改为在.h文件中new一下private static Socket instance=new Socket();
    是立即加载的方式,无论是否会用到这个对象,都会加载。
    如果在构造方法里写了性能消耗较大,占时较久的代码,比如建立与数据库的连接,那么就会在启动的时候感觉稍微有些卡顿。
    ==所以懒汉还是饿汉得根据项目实际情况来看

   [双重校验检索方法(应用在多线程场景中)]
    static QMutex mutex;
    static Socket *instance;
        if(!instance)
        {
            QMutexLocker locker(&mutex);//加锁,锁内只有一个线程执行
            if(!instance)//先执行的线程会进入内部new对象,后一个线程判断instance就不是NULL了
            {
                instance = new Socket;
            }
        }
        return instance;

   [单例模式的优缺点]
    优点:
    1、在内存里只有一个实例,减少了内存的开销,尤其是频繁的创建和销毁实例(比如管理学院首页页面缓存)。
    2、避免对资源的多重占用(比如写文件操作)。
    缺点:没有接口,不能继承,与单一职责原则冲突,一个类应该只关心内部逻辑,而不关心外面怎么样来实例化。

[链接_5个积分](26条消息) QT单例模式、多线程、双重校验加锁资源-CSDN文库

你可能感兴趣的:(单例模式,qt,开发语言)