单例模式(对象创建型)c++

单例模式是:保证一个类仅有一个实例,并提供该一个访问它的全局访问点。

通常可以让一个全局变量是的一个对象被访问,但它不能防止你实例化多个对象。一个好的方法就是,让类自身负责保存它的唯一实例。这个类可以保证没有其他实例被创建(将构造方法定义为私有的或保护的),并且提供一个访问该实例的方法(static方法)。这个实例是类的static变量,对于这个类只有一份。取得实例的方法是静态的,因为构造函数是私有的,所以只能通过类对象直接获得,所以方法也只能定义为静态的。不然无法获得实例。

单例模式最基本的分为两种:饿汉式、懒汉式

饿汉模式是:自己被加载时就将自己实例化。即定义时直接定义为类的一个对象。

另外因为定义的静态变量pInstance是一个指针,可以将一个指向Singleton子类的指针赋给这个变量。

这种是懒汉式单例类:即第一次被引用时,才将自己实例化。即pInstance被初始化为NULL, 而实际初始化是在函数中。懒汉式单例模式存在的问题是,当多线程环境下会出现同步问题,需要控制。


以下为饿汉懒汉实现代码:

单例模式:保证一个类仅有一个实例,并提供一个访问它的全局访问点
#include <iostream>
using namespace std;

//这种是饿汉式单例模式,即在类被构造出来后就将实例构造出来,
//会提前占用系统资源
class HungrySingleton
{
public:
    //这种是饿汉式单例模式,即在类被构造出来后就将实例构造出来,
    //会提前占用系统资源
    static HungrySingleton *getInstance()
    {
        return instance;
    }
private:
    HungrySingleton()
    {}
    static HungrySingleton* instance;
};
//这里是关键,直接初始化为类的对象,因为是类内数据,所以可以调用构造函数
HungrySingleton* HungrySingleton::instance = new HungrySingleton;


//这种是懒汉式单例模式,即在使用时才将实例构造出来,
//但这个会出现线程同步问题。
class LazySingleton
{
public:
    //函数必须是静态的,否则无法访问
    static LazySingleton *getInstance()
    {
        //如果两个线程同时进入getinstance,同时执行,则有两个实例被构造出来
        if (instance == NULL)
            instance = new LazySingleton();
        return instance;
    }
private:
    //构造函数私有的,不能再外部定义实例
    LazySingleton()
    {}
    static LazySingleton* instance;
};
//初始化为0
LazySingleton* LazySingleton::instance = 0;


int main()
{
    HungrySingleton *h1 = HungrySingleton::getInstance();
    HungrySingleton *h2 = HungrySingleton::getInstance();

    cout << "饿汉式单例模式运行结果:" << endl;
    if (h1 == h2)
        cout << "是同一个对象" << endl;
   
    LazySingleton *h3 = LazySingleton::getInstance();
    LazySingleton *h4 = LazySingleton::getInstance();

    cout << "懒汉式单例模式运行结果:" << endl;
    if (h3 == h4)
        cout << "是同一个对象" << endl;
    return 0;
}

为了解决懒汉式的多线程同步问题,加入锁,使用了互斥量,下面是实现代码:

#include <iostream>
#include <pthread.h>
using namespace std;

//解决懒汉式单例模式的多线程同步问题,即在new对象前加上锁,锁的实现在
//linux下采用mutex就够了,因为与顺序无关,只要保证一个时间只有一个线程就行了

class ThreadLazySingleton
{
public:
    static ThreadLazySingleton* getInstance(pthread_mutex_t mutex)
    {
        if (instance == NULL)
        {
            pthread_mutex_lock(&mutex);
            //双重检查,因为如果有两个线程同时通过第一个条件判断,进入到
            //内部条件,然后一个线程先申请到互斥量,之后如果为NULL,创建,
            //但它退出后,已经分配了一个,所以必须再次重新判断一次是否为
            //NULL,否则会再次分配一个对象。
            if (instance == NULL)
            {
                instance = new ThreadLazySingleton;
                cout << "getInstance():" << instance << endl;
            }
            pthread_mutex_unlock(&mutex);
            return instance;
        }
    }
private:
    ThreadLazySingleton() {}
    static ThreadLazySingleton *instance;
};

ThreadLazySingleton* ThreadLazySingleton::instance = NULL;

void *th_fn1(void *args)
{
    cout << "线程" << pthread_self() << "开始运行" << endl;
    pthread_mutex_t *mutex = (pthread_mutex_t*)args;
    ThreadLazySingleton *p = ThreadLazySingleton::getInstance(*mutex);
    cout << p << endl;
    pthread_exit((void*)p);
}

int main()
{
    pthread_mutex_t mutex;
    pthread_mutex_init(&mutex, NULL); //初始化互斥量

    int err;
    pthread_t tid1, tid2;
    ThreadLazySingleton* p1;
    ThreadLazySingleton* p2;
    err = pthread_create(&tid1, NULL, th_fn1, &mutex);
    if (err != 0)
        cout << "创建线程" << tid1 << "错误!" << endl;
    err = pthread_create(&tid2, NULL, th_fn1, &mutex);
    if (err != 0)
        cout << "创建线程" << tid2 << "错误!" << endl;
    pthread_join(tid1, (void**)&p1);
    pthread_join(tid2, (void**)&p2);
    //pthread_mutex_destory(&mutex);

    if (p1 == p2)
        cout << "同一个对象,同步正确" << endl;
    cout << p1 <<" " << p2 << endl;
    return 0;
}


以上是目前所学到的单例模式的内容。以后会不定时再补充~~


©️2020 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页