zoukankan      html  css  js  c++  java
  • 设计模式 --> (2)单例模式

    单例模式

      单例模式也称为单件模式、单子模式,可能是使用最广泛的设计模式。其意图是保证一个类仅有一个实例,并提供一个访问它的全局访问点,该实例被所有程序模块共享。如系统的日志输出,GUI应用必须是单鼠标,MODEM的联接需要一条且只需要一条电话线,操作系统只能有一个窗口管理器,一台PC连一个键盘。单例模式有两种:饿汉式单例类懒汉式单例类。

    适用性:

      单例模式常常与工厂模式结合使用,因为工厂只需要创建产品实例就可以了,在多线程的环境下也不会造成任何的冲突,因此只需要一个工厂实例就可以了。

    优点:

      1.减少了时间和空间的开销(new实例的开销)。

      2.提高了封装性,使得外部不易改动实例。

    缺点:

      1.懒汉式是以时间换空间的方式。

      2.饿汉式是以空间换时间的方式。

    饿汉式单例类

    //外部初始化 before invoke main
    const Singleton* Singleton::m_instance = new Singleton;
    
    class Singleton
    {
    private:
        static const Singleton* m_instance;
        Singleton(){}
    public:
        static const Singleton* getInstance()
        {
            return m_instance;
        }
    };

    懒汉式单例类

    class Singleton
    {
    private:
        static Singleton* m_instance;
        Singleton() {}
    public:
        static Singleton* getInstance();
    };
    
    Singleton* Singleton::getInstance()
    {
        if(NULL == m_instance)
        {
            m_instance = new Singleton;
        }
    
        return m_instance;
    }

    但是在多线程的环境下却不行了,因为很可能两个线程同时运行到if (m_instance == NULL)这一句,导致可能会产生两个实例。于是就要在代码中加锁。

    Singleton* getInstance()
    {
        lock();
        if (instance == NULL)
        {
           instance= new Singleton();
        }
        unlock();
    
        return instance;
    }

    但这样写的话,会稍稍影响性能,因为每次判断是否为空都需要被锁定,如果有很多线程的话,就爱会造成大量线程的阻塞。于是大神们又想出了双重锁定。

    Singleton* getInstance()
    {
        if (instance == NULL)
        {
            lock();
            if (instance == NULL)
            {
                   instance = new Singleton();
            }
            unlock();
        }
    
        return instance;
    }

    这样只够极低的几率下,通过越过了if (instance == NULL)的线程才会有进入锁定临界区的可能性,这种几率还是比较低的,不会阻塞太多的线程,但为了防止一个线程进入临界区创建实例,另外的线程也进去临 界区创建实例,又加上了一道防御if (instance == NULL),这样就确保不会重复创建了。

    使用

    #include <iostream>
    using namespace std;
    
    // 单例模式
    class Singleton
    {
    private:
        Singleton() {}; // 不允许直接构造其对象
        static Singleton *instance;
    
    public:
        static Singleton* createInstance()
        {
            if(!instance)
            {
                // 对象第一次被创建,允许
                cout << "创建新对象" << endl;
                instance = new Singleton();
            }
            else
            {
                // 请求再次创建对象,不允许
                cout << "已经创建过对象了,返回原对象" << endl;
            }
    
            return instance;
        }
    
        void getAddress()
        {
            cout << "我的地址是 " << instance << endl;
        }
    };
    
    Singleton* Singleton::instance = 0; //在初始化的时候,不能在前面加static了
    
    int main()
    {
        //Singleton s;//报错:无法访问 private 成员(在“Singleton”类中声明)
        Singleton *s1 = Singleton::createInstance();
        s1->getAddress();
        cout << endl << endl;
        
        Singleton *s2 = Singleton::createInstance();
        s2->getAddress();
        return 0;
    }
  • 相关阅读:
    Unix网络编程中的五种IO模型
    go工具库分析——go-snowflake
    defer
    滑动窗口
    快速幂
    Golang使用注意点
    微服务数据一致性基础认知
    KMP算法
    单调栈和单调队列
    LRU简单学习
  • 原文地址:https://www.cnblogs.com/jeakeven/p/4911930.html
Copyright © 2011-2022 走看看