设计模式——单例模式(慢加载)

来源:互联网 发布:linux文件系统书籍 编辑:程序博客网 时间:2024/06/05 22:46

这篇文章总结几种比较常用的设计模式,,,不懂得设计模式。。。怎么敢称熟悉OOP思想。

单例模式的核心结构中只包含一个被称为单例类的特殊类,通过单例模式可以保证系统中一个类只有一个实例

由于快加载单例模式是线程安全的,所以本文只讨论慢加载单例模式的线程安全问题

版本一 使用慢加载(懒加载),程序调用时再分配内存,然后初始化


class Singleton{public:    static Singleton* getInstance()  //该公有接口专门返回对象实例    {        if(sobj == NULL)        {            sobj = new Signleton();//慢加载,程序调用时才生分配内存        }        return sobj;    }private:    Singlenton(){};  //私有化构造函数    static Singlenton *sobj;}signlenton* signlenton::sobj = NULL;//慢加载,程序调用时才会生成,然后初始化

上述代码存在线程安全问题,if语句非原子操作,多线程调用时,会存在竞态条件

版本二 使用慢加载,考虑到多线程安全问题,使用互斥锁可以解决

1,考虑多线程调用时,是否存在竞态条件
2,考虑竞态条件,是否随着线程调度顺序的不同,而出现了不同的运行结果
3,发生竞态条件的代码段称为临界区代码段,临界区代码段都满足原子操作,为了保证原子操作,需要给临界区的代码段加上互斥锁进行控制,if语句不是原子操作,需要加互斥锁


class Singleton{public:    static Singleton* getInstance()  //该公有接口专门返回对象实例    {        pthread_mutex_lock(&mutex);//加锁        if(sobj == NULL)        {            sobj = new Signleton();//慢加载,程序调用时才生分配内存        }        pthread_mutex_unlock(&mutex);//解锁        return sobj;    }    ~Singlenton()    {        pthread_mutex_destroy(&mutex);//锁的销毁    }private:    Singlenton(){};  //私有化构造函数    static Singlenton *sobj;    static ptheread_mutex_t mutex;}signlenton* signlenton::sobj = NULL;//慢加载,程序调用时才会生成,然后初始化pthread_mutex_t Singleton::mutex = PTHREAD_MUTEX_INITIALIZER;//锁的初始化

上述互斥锁满足了 if语句的原子操作,实现了线程安全,但由于程序每调用一次,就会产生加锁解锁操作,对于单线程而言,降低了效率,所以代码还需要解决单线程的效率问题

版本三 由于存在单线程和多线程共存问题,提高单线程效率,需要使用双if语句


1,单线程存在效率低的问题,需要第二次调用的时候返回false
2,多线程仍需要注意竞态条件

class Singleton{public:    static Singleton* getInstance()  //该公有接口专门返回对象实例    {        if(sobj == NULL)  //双if语句,第二次调用不用进行加锁解锁操作        {            pthread_mutex_lock(&mutex);//加锁            if(sobj == NULL)            {                sobj = new Signleton();//慢加载,程序调用时才生分配内存            }            pthread_mutex_unlock(&mutex);//解锁        }        return sobj;    }    ~Singlenton()    {        pthread_mutex_destroy(&mutex);//锁的销毁    }private:    Singlenton(){};  //私有化构造函数    static Singlenton *sobj;    static ptheread_mutex_t mutex;}signlenton* signlenton::sobj = NULL;//慢加载,程序调用时才会生成,然后初始化pthread_mutex_t Singleton::mutex = PTHREAD_MUTEX_INITIALIZER;//锁的初始化

上述代码提高了单线程效率,并实现线程是安全的,调用多线程时,当锁被释放后,线程缓存sobj的值刷新到原始内存中了,所以下次取值是在内存中取,是线程安全的。

原创粉丝点击