设计模式之单例模式

链接: link
https://www.jianshu.com/p/edab2673ee6c

单例模式

定义:

  • 保证一个类仅有一个实例,并提供一个该实例的全局访问点
  • 创建一个对象,确保只有一个对象被创建

全局变量和单例的区别

全局变量是对一个对象的静态引用,全局变量确实可以提供单例模式实现的全局访问功能,但是它并不能保证应用程序只有一个实例全局变量并不能实现继承

应用场景:

  • Windows的Task Manager(任务管理器)就是很典型的单例模式,你不能同时打开两个任务管理器。Windows的回收站也是同理。
  • 应用程序的日志应用,一般都可以用单例模式实现,只能有一个实例去操作文件。
  • 读取配置文件,读取的配置项是公有的,一个地方读取了所有地方都能用,没有必要所有的地方都能读取一遍配置。
  • 数据库连接池,多线程的线程池

懒汉式:[线程不安全版本]

class Singleton{
public:
    static Singleton* getInstance(){
        // 先检查对象是否存在
        if (instance == nullptr) {
            instance = new Singleton();
        }
        return instance;
    }
private:
    Singleton(); //私有构造函数,不允许使用者自己生成对象
    //Singleton(const Singleton& other);
    static Singleton* instance; //静态成员变量 
};
//静态成员需要先初始化
Singleton* Singleton::instance=nullptr; 

饿汉式:(可以不看)

class Singleton{
public:
    static Singleton* getInstance(){
        instance = new Singleton();
        return instance;
    }
private:
    Singleton(); //私有构造函数,不允许使用者自己生成对象
    //Singleton(const Singleton& other);
    static Singleton* instance; //静态成员变量 
};

实现二[线程安全,锁的代价过高]

//线程安全版本,但锁的代价过高
Singleton* Singleton::getInstance() {
    Lock lock; //伪代码 加锁
    if (instance == nullptr) {
        instance = new Singleton();
    }
    return instance;
}

分析:这种写法不会出现上面两个线程都执行new的情况,当线程A在执行instance = new Singleton()的时候,线程B如果调用了getInstance(),一定会被阻塞在加锁处,等待线程A执行结束后释放这个锁。从而是线程安全的。但这种写法的性能不高,因为每次调用getInstance()都会加锁释放锁,而这个步骤只有在第一次newSingleton()才是有必要的,只要instance被创建出来了,不管多少线程同时访问,使用if (instance ==nullptr)进行判断都是足够的(只是读操作,不需要加锁),没有线程安全问题,加了锁之后反而存在性能问题

实现三[双检查锁,由于内存读写reoder导致不安全]

//双检查锁,但由于内存读写reorder不安全
Singleton* Singleton::getInstance() {
    //先判断是不是初始化了,如果初始化过,就再也不会使用锁了
    if(instance==nullptr){
        Lock lock; //伪代码
        if (instance == nullptr) {
            instance = new Singleton();
        }
    }
    return instance;
}

最安全的实现方式

局部静态变量不仅只会初始化一次,而且还是线程安全的。

class Singleton{
public:
    // 注意返回的是引用。
    static Singleton& getInstance(){
        static Singleton instance;  //局部静态变量
        return instance;
    }
private:
    Singleton(); //私有构造函数,不容许使用者本身生成对象
    Singleton(const Singleton& other);
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值