单例模式

浅析设计模式——单例模式
1、单例类的好处之一在于唯一化实例、从而可以实现对唯一实例的受控访问
该唯一性是通过将构造函数私有来实现的,既然构造函数被设置为private,那么外部函数将不能调用构造函数来创建实例(比如在外部函数中编写Singleton* singletonptr=new Singleton();将会报错)。
那么问题来了,单例类虽然只能创建一个实例,但终归是要能创建嘛。为了实现创建这个唯一的实例,需要在单例类中定义一个public的静态成员函数GetInstance(),外部函数通过这个公有的接口来获取这个唯一的实例。(之所以用到static,是因为静态成员函数同一般函数的区别在于没有this指针,对于静态函数而言,没有this指针也就意味着即使没有对象也能调用它(单例类常会用到静态成员函数和静态数据成员)。外部函数既然都不能直接实例化对象,又要调用该单例类的public成员函数,那么就需要将该成员函数设置为静态成员函数。)
在公有的静态成员函数GetInstance()中,需要先判断是否已经实例化,如果已经实例化则直接返回该实例,如果没有才会创建一个实例;
Singleton* Singleton::GetInstance() {
if(instance==NULL) {
instance=new Singleton();
}
return instance;
}
对于下列代码中有一行很重要,不要遗漏:
Singleton* Singleton::instance = new Singleton();
这一行是为了实例化这个唯一的对象,这是饿汉式,如果直接赋值为NULL则是懒汉式
2、单例类虽然实例单一、但是可以有子类来继承;
3、单例类还分为恶汉式单例类和懒汉式单例类,此外多线程时还需要有其他的考虑(比如加锁)。

考虑所有情况以后的单例模式代码,Linux下编译通过:
#include<iostream>
#include<pthread.h>
using namespace std;
 
pthread_mutex_t mutex;
 
class Singleton{
public:
    static Singleton* GetInstance();  //获取唯一实例接口
private:
    Singleton();            //私有的构造函数
    static Singleton* instance;    //唯一的实例
};
 
Singleton::Singleton() {
}
 
//Singleton* Singleton::instance = new Singleton();  //饿汉式,空间换时间懒汉式和饿汉式对线程安全的不同影响
Singleton* Singleton::instance = NULL; //懒汉式,时间换空间
 
Singleton* Singleton::GetInstance() {
    if (instance == NULL) {             //二次判断!!!
        pthread_mutex_lock(&mutex);      //static int* volatile instance=0/new Singleton();
        if (instance == NULL){     //用volatile关键字告诉编译器此处的变量instance很有可能被其他地方改变,不能进行优化
            instance = new Singleton();   //还有此处的CPU乱序问题,导致指针指向还没有被构造出来的内存
        }
        pthread_mutex_unlock(&mutex);
    }
    return instance;
}
 
int main(){
    pthread_mutex_init(&mutex, NULL);
    Singleton*  singleton1 = Singleton::GetInstance();
    Singleton*  singleton2 = Singleton::GetInstance();
    if (singleton1 == singleton2)    //判断这两个实例是否是同一个
        cout << "we are the same instance" << endl;
    pthread_mutex_destroy(&mutex);
    return 0;
}
4、CPU乱序问题:
1>用volatile关键字告诉编译器此处的变量instance很有可能被其他地方改变,不能进行优化
static int* volatile instance=0/new Singleton();
2>instance=newSingleton();实质上由三个步骤组成:1分配内存、2在内存的位置上调用构造函数、3将内存地址赋值给指针instance。由于CPU的乱序执行,很有可能将步骤2和3颠倒,此时会出现一种情况就是;还未调用构造函数就把内存地址赋值给了指针,假如有另一个线程调用getInstance函数,那么由于Instance指针非空,该线程就会获取到这个非空但并没有构造完全的对象指针,如果使用该指针的话,会带来很恶劣的影响。
解决方法:使用barrier指令阻止CPU将该指令之前的指令交换到该指令之后
  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值