精华内容
下载资源
问答
  • 单例模式中的饿汉和懒汉模式
    2022-02-28 15:52:29

    目录

    一.什么是单例模式

    一.饿汉模式

    1.饿汉模式的概念

    2.饿汉模式代码

    2.多线程是否线程安全

    二.懒汉模式

    1.懒汉模式的概念

    2.单线程情况下的懒汉模式

    2.多线程情况下的懒汉模式

    (1)导致懒汉模式在多线程情况下的不安全原因

    (2)解决方法代码示例

    版本1

    版本2

    版本2的解释说明


    一.什么是单例模式

    保证某个类在程序中只存在一份实例,而不会创建多个实例,这样就会提高效率。

    在单利模式中一般只提供一个getInstance()方法来获取实例对象,不提供setInstance()方法,目的是为了避免再实例化出其他实例对象。

    其中单例模式中有两种模式一种是饿汉模式,一种是懒汉模式。

    一.饿汉模式

    1.饿汉模式的概念

    饿汉模式就是在类加载的时候立刻会实例化,后续使用就只会出现一份实例。

    2.饿汉模式代码

    package thread.example;
    //饿汉模式
    public class HungrySingle {
    //在类加载的时候就实例化了,类加载只有一次,所以值实例化出了一份该实例对象
        private static HungrySingle instance = new HungrySingle();
        public static HungrySingle getInstance() {
            return instance;
        }
    }

    2.多线程是否线程安全

    在类加载的时候就已经实例化了,所以该实例化没有涉及到实例化的修改操作,只是进行读取操作。在多线程情况下是线程安全的。 

    二.懒汉模式

    1.懒汉模式的概念

    在类加载的时候没有直接实例化,而是调用指定实例方法的时候再进行实例化,这样就能保证不想使用的时候也不会实例化。一般来说比饿汉模式的效率高。

    2.单线程情况下的懒汉模式

    package thread.example;
    //单线程的懒汉模式
    public class LazySingle {
        private static LazySingle instance = null;
        //只有在调用该方法的时候才实例化
        public static LazySingle getInstance() {
            if(instance == null) {
                instance = new LazySingle();
            }
            return instance;
        }
    }

    2.多线程情况下的懒汉模式

    (1)导致懒汉模式在多线程情况下的不安全原因

    在多线程的情况下,由于可能两个线程都会得到一份instance=null,这是因为如果线程1修改了自己县城中的instance后还没来得及修改主内存中的instance,所导致线程2也实例化出了一份instance对象,这时候也就不再是单例模式了。主要导致该问题的是由于这里面涉及到了对instance的修改操作,失去了原子性,为了保证原子性,我们想到了加锁,从而实现线程安全问题。

    (2)解决方法代码示例

    版本1

    package thread.example;
    //多线程安全下的懒汉模式
        public class LazySingle {
            private LazySingle() {
        }
        private static LazySingle instance = null;
        //只有在调用该方法的时候才实例化
        public static synchronized LazySingle getInstance() {
            if (instance == null) {
                instance = new LazySingle();
            }
            return instance;
        }
    }

    版本1的代码虽然保证了线程安全,但是每次调用该方法时还是会出现加锁解锁问题,为了进一步优化,我们可以减小锁的粒度来提高效率,因为加了锁之后也就和高并发无缘了,但我们还是想提高效率,所以才会进行优化。

    版本2

    双重if判断加锁提高效率

    package thread.example;
    
    public class SecurityLazyModle {
        private LazySingle() {
        }
        private static volatile SecurityLazyModle instance = null;//保证内存可见性,防止编译器过度优化(指令重排序)
        public static SecurityLazyModle getInstance() {
            if(instance == null) {
                synchronized (SecurityLazyModle.class) {
                    if(instance == null) {
                        instance = new SecurityLazyModle();
                    }
                }
            }
            return instance;
        }
    }
    

    版本2的解释说明

    第一层if是为了判断当前是否已经把实例创建出来,第二层synchronized是为了使进入当前if中的线程来竞争锁,当拿到锁的线程进入到第三层if之后判断是否为空,不为空就是实例化对象,然后再释放锁,释放锁之后,instance已经不为空了,后面的线程就被阻挡在了第三层if这里了,之后再来访问getInstance()方法,发现该instance已经不为空了,也就不用再抢占锁资源了,因为竞争锁也消耗大量的时间。通过这样处理,既保证了线程安全,也提高了效率。

    这里使用volatile是为了防止编译器优化导致的指令重排序,在进行new一个对象不是原子性操作,可以分为三步骤:

    1.分配内存空间

    2.实例化对象

    3.给变量赋值

    对于上面的执行,如果1和3先执行了(假设2还没有完成),在第一层if外的线程这时候判断不为null,这时候就会直接返回该对象,但是这个对象只执行了一半,之后使用就会导致线程安全问题。

    通过volatile就可以确保这3步骤必须执行完(无论顺序如何,最终都会执行完),外面的线程才可以执行,这时候就保证了该对象的完整性。

    更多相关内容
  • 对于懒汉模式,我们可以这样理解:该单例类非常懒,只有在自身需要的时候才会行动,从来不知道及早做好准备。它在需要对象的时候,才判断是否已有对象,如果没有就立即创建一个对象,然后返回,如果已有对象就不再...
  • 饿汉模式、懒汉模式、DCL单例模式、枚举;不同情况下使用不同的单例创建模式
  • 饿汉模式和懒汉模式

    2018-07-03 11:13:19
    单例模式中,包括饿汉模式和懒汉模式,这是饿汉模式和懒汉模式的区别
  • 懒汉模式是一种思想,是一种开发程序的规范
  • 这里写目录标题懒汉模式饿汉模式线程安全的懒汉模式 懒汉模式 懒汉模式在第一次用到类实例的时候才会去实例化,就是不到调用getInstance函数时,这个类的对象是一直不存在的。懒汉本身是线程不安全的。 #include <...

    懒汉模式

    懒汉模式在第一次用到类实例的时候才会去实例化,就是不到调用getInstance函数时,这个类的对象是一直不存在的。懒汉本身是线程不安全的

    #include <iostream>
    using namespace std;
     
    class Singelton{
    private:
        Singelton(){
            m_count ++;
            printf("Singelton begin\n");
            Sleep(1000);// 加sleep为了放大效果
            printf("Singelton end\n");
        }
        static Singelton *single;//定义一个唯一指向实例的指针,并且是私有的
    public:
        static Singelton *GetSingelton();//定义一个公有函数,可以获取这个唯一实例
        static void print();
        static int m_count;
    };
     
     //将唯一指向实例的指针初始化为nullptr
    Singelton *Singelton::single = nullptr;
    int Singelton::m_count = 0;
     
    Singelton *Singelton::GetSingelton(){
        if(single == nullptr){//判断是不是第一次使用
            single = new Singelton;
        }
        return single;
    }
     
    void Singelton::print(){
        cout<<m_count<<endl;
    }
    
    int main()
    {
    	singleton* a1 = singleton::GetInstance();
    	cout << a1 << endl;
    	a1->print();
    
    	singleton* a2 = singleton::GetInstance();
    	cout << a2 << endl;
    	a2->print();
    	system("pause");
    	return 0;
    }
    

    懒汉模式的singleton类有以下特点:

    1. 他有一个指向唯一实例的静态指针,并且是私有的。
    2. 它有一个公有的函数,可以获取这个唯一的实例,并且在需要的时候创建该实例。
    3. 它的构造函数是私有的,这样就不能从别处创建该类的实例。

    饿汉模式

    饿汉模式在单例类定义的时候(即在main函数之前)就进行实例化。因为main函数执行之前,全局作用域的类成员静态变量m_Instance已经初始化,故没有多线程的问题。

    #include <iostream>
    #include <process.h>
    #include <windows.h>
    using namespace std;
     
    class Singelton{
    private:
        Singelton(){
            m_count ++;
            printf("Singelton begin\n");
            Sleep(1000);                            // 加sleep为了放大效果
            printf("Singelton end\n");
        }
        static Singelton *single;//定义一个唯一指向实例的指针,并且是私有的
    public:
        static Singelton *GetSingelton();//定义一个公有函数,可以获取这个唯一实例
        static void print();
        static int m_count;
    };
    
    // 饿汉模式的关键:定义即实例化
    Singelton *Singelton::single = new Singelton;
    int Singelton::m_count = 0;
     
    Singelton *Singelton::GetSingelton(){
        // 不再需要进行实例化
        //if(single == nullptr){
        //    single = new Singelton;
        //}
        return single;
    }
     
    void Singelton::print(){
        cout<<m_count<<endl;
    }
    
    int main()
    {
    	cout << "we get the instance" << endl;
    	singleton* a1 = singleton::getinstance();
    	singleton* a2 = singleton::getinstance();
    	singleton* a3 = singleton::getinstance();
    	cout << "we destroy the instance" << endl;
    	system("pause");
    	return 0;
    }
    

    线程安全的懒汉模式

    在多线程环境下,懒汉模式的上述实现方式是不安全的,原因在于在判断instance是否为空时,可能存在多个线程同时进入if中,此时可能会实例化多个对象。于是出现了二重锁的懒汉模式,实现代码如下:

    #include <iostream>
    using namespace std;
     
    class Singelton{
    private:
        Singelton(){
            m_count ++;
            printf("Singelton begin\n");
            Sleep(1000);// 加sleep为了放大效果
            printf("Singelton end\n");
        }
        static Singelton *single;//定义一个唯一指向实例的指针,并且是私有的
    public:
        static Singelton *GetSingelton();//定义一个公有函数,可以获取这个唯一实例
        static void print();
        static int m_count;
        static mutex i_mutex;//锁
    };
     
     //类外初始化,将唯一指向实例的指针初始化为nullptr
    Singelton *Singelton::single = nullptr;
    int Singelton::m_count = 0;
    mutex Singelton::i_mutex;
    
    Singelton *Singelton::GetSingelton(){
    	//双重锁模式
    	//因为获取锁是很浪费时间的,因此先判断single是否为空,如果为空则进入,不为空说明已经存在实例,直接返回。
    	if (single == nullptr){
    		//进入后加锁
    		i_mutex.lock();
    		//再判断一次,因为可能有多个线程在lock处等待,一个线程成功之后,会将single设置为非空,这样下个线程就算拿到lock资源,再进去发现指针非空就离开了。
    		if (single == nullptr){
    				single = new lhsingleClass();
    			}
    		i_mutex.unlock();//解锁
    	}
    	return single ;
    }
     
    void Singelton::print(){
        cout<<m_count<<endl;
    }
    
    int main()
    {
    	singleton* a1 = singleton::GetInstance();
    	cout << a1 << endl;
    	a1->print();
    
    	singleton* a2 = singleton::GetInstance();
    	cout << a2 << endl;
    	a2->print();
    	system("pause");
    	return 0;
    }
    

    此代码共进行了两次判断:

    • 先判断是否为空,如果为空则进入,不为空说明已经存在实例,直接返回。
    • 再判断一次,因为可能有多个线程在lock处等待,一个线程成功之后,会将single设置为非空,这样下个线程就算拿到lock资源,再进去发现指针非空就离开了。
    展开全文
  • 目录案列一:线程安全的单例模式饿汉模式懒汉模式 案列一:线程安全的单例模式 线程安全的单例模式是面试中常见的问题,所以熟练掌握这种单例模式尤为重要 什么叫单例模式? 单例模式就是一种设计模式,写代码时一种常见...

    🥝线程安全的单例模式

    线程安全的单例模式是面试中常见的问题,所以熟练掌握这种单例模式尤为重要
    什么叫单例模式?
    单例模式就是一种设计模式,写代码时一种常见的应用场景,设计模式就是针对于这些应用场景给出的解决方案,我们可以把它想成为棋谱,这种棋谱就是由那些“围棋高手”(大佬程序猿)留下来便于小白🥬使用
    而且我们还需要知道单例模式的效果就是保证某个类只有唯一实例

    单例模式分为饿汉模式和懒汉模式

    🥝饿汉模式

    顾名思义,饿汉模式就是表示比较着急的去干某件事,这里的饿汉并不是代表真的饿了,而是代表急不可待的意思
    举个🌰 :小明假期留了三本大作业,结果放假第一天,小明就照着答案把这些作业全都写完了,于是小明的假期就变的甚是潇洒,显然,这种做法是不可取的,虽然速度提上去了,但是并没有什么卵用

    我么可以引出饿汉的单例模式就是比较着急的去创建线程

    下面我们就用代码来演示一下饿汉的单例模式

    创建一个Singleton类(我们要知道singleton这个单词的意思,如果singleton大家不知道那么singledog的意思大家一定要知道,没错就是你“单身狗🐶 的意思”,那么singleton就是单个的意思),通过这个类来保证单例模式只有唯一的实例

    *
    线程安全的单例模式实现-饿汉模式
     */
        class Singleton{
            //1.使用static创建一个实例,并且立即进行实例化,
            //这个instance对应的实例,是该类的唯一实例.
            private static Singleton instance = new Singleton();
            //2.为了防止程序猿在其他的地方不小心的new了这个Singleton,把构造方法设为private
            private Singleton(){}
            //3.提供一个方法,让类外能拿到这个唯一实例
            public static Singleton getInstance(){
                return instance;
            }
    }
    public class TestDemo1 {
        public static void main(String[] args) {
            Singleton instance = Singleton.getInstance();
        }
    }
    

    上述代码中,static是用来修饰类成员(类属性/类方法),一个Java程序中,一个类对象只存在一份(JVM保证的),这样也就保证了static修饰的实例只有一份了
    static是单例模式实现的主要方法

    🥝懒汉模式

    举🌰 :小红和小明是同班同学,小明为了能够愉快的过假期,一天的时间内写完了所有的作业,小红不同,小红是个好学生,她给自己定了个计划,每天写一点,而且很认真独立完成作业,在照着答案批改,写完作业后再去玩,就这样,小红用了一个假期写完了所有作业,开学后,小明受了老师的惩罚,小红却得到了表扬

    写到这里,可能就会有同学会问,那为什么把这种模式叫做懒汉模式呢
    我们需要知道,在计算机中是一种褒义词,并不是我们日常生活中的懒,
    这种懒会让系统变得更高效,系统什么时候有时间,系统再去工作,而不是一股脑的把工作全给做完

    我们可以看出懒汉模式的单例模式就是什么时候需要去做的时候,系统才回去创建实例,而不是一股脑的把实例全都创建出来

    下面我们就用代码来演示一下懒汉的单例模式`

    *
    线程安全的单例模式实现-懒汉模式(只有真正的使用到getInstance的时候才真正的创建实例)
     */
    class Singleton2{
        //1.和饿汉模式有所不同,此模式并不是立即初始实例
        private static volatile Singleton2  instance = null;
        //2.将构造方法设为private
        private Singleton2(){}
        //3.提供一个方法获取实例,但是只有真正需要的时候才会真正的去创造实例
        public static Singleton2 getInstance(){
                    if(instance==null){
                        instance = new Singleton2();
                    }
            return instance;
        }
    }
    

    和饿汉模式有所不同,此模式并不是立即初始实例,而是判断一下是否真的需要,只有在真正的需要的时候才会去创建实例

    以上是懒汉模式的雏形,但是,我们随着深入了解,会发现,懒汉模式存在许多问题

    if(instance==null){
         instance = new Singleton2();
       }
    

    这两行代码即包含了读操作,也包含了修改操作,而且这两行代码是两个步骤,不是原子性的(何为原子性,可以去了解我之前写的线程安全问题的博客),也就是说此代码存在线程安全问题

    线程安不安全,具体的多线程环境下,并发的调用getInstance,是否存在BUG

    请添加图片描述
    如图解:我们不难看出,如果读操作和修改操作不是原子性的,就可能会导致多个线程创造出多个实例出来,就违背了我们的初衷,实现多线程的单例模式

    所以,我们需要加锁操作:

    synchronized(Singleton2.class){
                       if(instance==null){
                           instance = new Singleton2();
                       }
                       return instance;
                   }
        }
    

    上述代码使用了类对象作为了锁对象,类对象在程序中只存在一份,就能保证了多线程在调用getInstance的时候都是针对同一个对象进行的加锁

    这样就保证了多操作和修改操作的原子性

    加了锁之后线程变得安全了,但是又产生了新的问题

    1. 线程不安全是因为没有加锁,在加了锁之后,instance已经被初始化了,那么此时的instance就一定不是null了,这样代码就只会进行if和return的两个读操作,线程也就变的安全了,根据上述的代码,我么会发现,无论是在初始化前,还是在初始化之后,getinstance都是会被一直加锁的,如果instance已经被初始化了,那么在对getinstance进行加锁就会产生不必要的锁竞争

    加锁虽然解决了线程安全问题,即开发效率,但是运行效率也随着降低,我们需要保证开发效率,也需要保证运行效率

    改进方案:让instance初始化之前,才进行加锁,初始化之后就不需要加锁了,所以在加锁之前,加上一个判定条件,条件就是当前instance是否已经完成

     if(instance==null){
                synchronized(Singleton2.class){
                    if(instance==null){
                        instance = new Singleton2();
                    }
                }
            }
            return instance;
    }
    

    有细心的同学可能会发现,上述两个if的判断条件是相通的,那么将所有的代码放在一个if条件里不就好了吗?
    这是绝对不可以的!!!
    因为代码如果是这样的

     if(instance==null){
                synchronized(Singleton2.class){
                        instance = new Singleton2();
                }
            }
            return instance;
    

    很明显,这样的代码没有保证读操作和修改操作的原子性,这也就代表着之前的所有铺垫都形同虚设了

    那为什么会出现这种情况呢?这完全是一种美丽的巧合
    1.第一个判定条件,是否需要加锁
    2.第二个判定条件是否需要对instance初始化
    这两个判定条件起到的效果/预期的目的是完全不一样的
    碰巧这两个判定条件都是instance是否为null

    在解决了上述代码后,还有最后一个重要的线程安全问题
    我么发现,上述代码如果是多个线程共同调用这里的getinstance,因为这个方法只有一个(单例模式),就会导致方法会有大量的读操作产生,前面我们说到,如果代码有大量的读操作,编译器就会把这个读内存操作优化成读寄存器操作,这也就是我们所说的线程安全问题之一:内存可见性,这可能会引起第一个if判定条件产生误差,第二个不会产生影响,因为关键字synchronized,所以我们需要对instance这个变量进行修饰

    1. 使用volatile关键字

    volatile可以保证变量不被编译器优化,但是不能保证原子性,此处我们只需要防止编译器优化即可

    //1.和饿汉模式有所不同,此模式并不是立即初始实例
        private static volatile Singleton2  instance = null;
        //2.将构造方法设为private
        private Singleton2(){}
        //3.提供一个方法获取实例,但是只有真正需要的时候才会真正的去创造实例
        public static Singleton2 getInstance(){
            if(instance==null){
                synchronized(Singleton2.class){
                    if(instance==null){
                        instance = new Singleton2();
                    }
                }
            }
            return instance;
            }
    

    🥝 懒汉模式总结

    单例模式是我们秋招面试时非常重要的一个问题,懒汉模式尤为重要,懒汉模式产生的问题我们也需要熟练掌握

    1. 在正确的位置加锁,保证读操作和修改操作的原子性
    2. 双重if判定,避免产生不必要的锁竞争
    3. 对instance使用关键字volatile,防止编译器优化

    以上就是对线程安全中单例模式的总结,此案列非常重要,是多线程经典的案例,大家应该熟练掌握相关代码,最后可以写出来

    展开全文
  • 懒汉模式-单线程(Lazy Singleton)2.1 简易版2.2 私有嵌套类-回收专用3、懒汉模式 -多线程版本4、懒汉模式 - 现代c++11-优雅的多线程版本 前言 单例模式是23种设计模式中最常用的一种模式。一个类只能创建一个对象...

    前言

    单例模式是23种设计模式中最常用的一种模式。一个类只能创建一个对象,让类自身负责保存它的唯一实例,并提供一个访问它的全局访问接口,这就是单例模式

    Singleton类单例模式
    -instance私有
    -Singeton()私有构造函数
    +GetInstance()访问接口,静态方法

    一、单例模式的应用场景

    1、windows桌面上,已打开了一个回收站,试图再次打开一个新的回收站时,Windows系统并不会为你弹出一个新的回收站窗口。,也就是说在整个系统运行的过程中,系统只维护一个回收站的实例。这就是一个典型的单例模式运用。

    2、网站的计数器,一般采用单例模式实现,如果存在多个计数器,每一个用户的访问都刷新计数器的值,计数值是难以同步的。但是如果采用单例模式本来就同步,而且还可以避免线程安全问题。

    3、服务器的配置信息,存放在一个文件中,这些配置数据由一个单例对象统一读取,然后服务进程中的其他对象再通过这个单例对象获取这些配置信息,这种方式简化了在复杂环境下的配置管理,如HttpApplication。

    适用场景如下:

    1. 需要生成唯一序列的环境
    2. 需要频繁实例化然后销毁的对象。
    3. 创建对象时耗资源过多,但又常用的对象。
    4. 方便资源相互通信的环境

    二、单例模式的实现

    从具体实现的角度来说:

    1. 该类提供了一个静态的公有函数用于创建或者获取它本身的静态私有对象;
    2. 类定义中含有一个该类的静态私有对象
    3. 单例模式的类只提供私有的构造函数,防止多个实例创建。

    1.饿汉式(Eager Singleton)

    饿了肯定要饥不择食。所以在单例类定义的时候,即一开始就进行实例化。(本身就是线程安全的,如下例子)

    class Singleton{
    public:
        static Singleton* GetInstance(){
            return &instance;  // 返回指针
        }
    private:
        static Singleton instance;
    
        Singleton(){};// 构造函数私有,防止外界利用new创建此实例,
        Singleton(const Singleton&) =delete; //防止拷贝
        Singleton& operator=(const Singleton&) =delete; //防止赋值
    
    };
    Singleton Singleton::instance; //在程序入口之前就完成单例对象的初始化
    

    由于在main函数之前初始化,所以没有线程安全的问题。但是潜在问题是no-local static对象(函数外的static对象)在不同编译单元中的初始化顺序是未定义的。也即static Singleton instancestatic Singleton& getInstance()二者的初始化顺序不确定,如果在初始化完成之前调用 getInstance() 方法会返回一个未定义的实例。

    2.懒汉模式-单线程(Lazy Singleton)

    即懒汉版(Lazy Singleton):单例实例在第一次被使用时才进行初始化,这叫做延迟初始化

    2.1 简易版

    class Singleton
    {
    private:
    	static Singleton* instance;
    private:
    	Singleton() {};
    	~Singleton() {};
    	Singleton(const Singleton&);
    	Singleton& operator=(const Singleton&);
    public:
    	static Singleton* getInstance() 
            {
    		if(instance == NULL) 
    			instance = new Singleton(); //如果实例不存在,则创建一个实例
    		return instance;
    	}
    };
    // init static member
    Singleton* Singleton::instance = NULL;
    

    但是以上代码存在new出来的对象内存泄露的和多线程竞争问题,当两个线程同时进入if (singleton == null)同时创建实例,导致单例模式失效的问题。

    2.2 私有嵌套类-回收专用

    内存泄漏问题可以使用共享指针解决,或者假如静态成员Deletor释放被new出来的单例对象

    // version 1.1
    class Singleton
    {
    private:
        static Singleton* instance;
    private:
        Singleton() { };
        ~Singleton() { };
        Singleton(const Singleton&);
        Singleton& operator=(const Singleton&);
    private:
        class Deletor {  //删除Singleton类
        public:
            ~Deletor() {
                if(Singleton::instance != NULL){
                    delete Singleton::instance;
                }
            }
        };
        static Deletor deletor; //静态成员对象,程序结束后 调用析构删除new对象
    public:
        static Singleton* getInstance() {
            if(instance == NULL) {
                instance = new Singleton();
            }
            return instance;
        }
    };
    
    // init static member
    Singleton* Singleton::instance = NULL;
    Singleton::Deletor Singleton::deletor;
    

    以上的Delete私有内嵌类的私有静态成员,利用程序结束时析构全局变量的特性,选择最终的释放时机;使用单例的代码不需要任何多余释放操作,不必关心对象的释放。

    3、懒汉模式 -多线程版本

    上述懒汉模式在单线程环境下是正确无误的,但在多线程环境就会出现race condition,要使其线程安全,我们首先想到的是利用同步机制来正确的保护我们的单例实例。可以使用**双重检测一重锁**模式(DCL: Double-Checked Locking Pattern):

    using namespace std;
    
    class Singleton{
    private:
        Singleton(){printf( "Singleton init\n");}
        ~Singleton(){printf( "delete Singleton \n");}
        Singleton(const Singleton&) =delete;
        Singleton& operator=(const Singleton&) =delete;
    private:
        class Delete{
        public:
            ~Delete(){
                if(Singleton::_instance!=nullptr){
                    delete Singleton::_instance;
                }
            }
        };
    private:
        static Singleton* _instance;
        static Delete _delete;
        static mutex _mtx;
    
    public:
        static Singleton* GetInstance()
        {
            if(_instance==nullptr){          //第一重检测,如果未初始化。
                lock_guard<mutex> lck(_mtx); // 上锁,RAII技法,离开if{},自动解锁
                if(_instance== nullptr){     //第二重检测,还未初始化,new
                    _instance = new Singleton();
                }
            }
            return _instance;
        }
    
    };
    Singleton* Singleton::_instance =nullptr;
    Singleton::Delete Singleton::_delete;
    mutex Singleton::_mtx;
    

    使用双重检测同步延迟加载去创建单例的做法是一个非常优秀的做法,其不但保证了单例,而且切实提高了程序运行效率,第一重检测可以避免无效上锁,导致运行速度过慢

    4、懒汉模式 - 现代c++11-优雅的多线程版本

    双重检测模式和私有嵌套类Delete实现起来代码量略长,c++11标准下,《Effective C++》提出了一种更优雅简易的多线程单例模式实现,使用函数内的 local static ,即static静态局部变量的初始化,编译器会自动加锁解锁这样,只有当第一次访问getInstance()方法时static静态局部变量才创建实例。

    class Singleton{
    private:
        Singleton(){printf("Singeleton init \n");};
        ~Singleton(){printf("delete Singeleton \n");};
        Singleton(const Singleton&) = delete;
        Singleton& operator=(const Singleton&) =delete;
    public:
        static Singleton* GetInstance(){
            static Singleton instance;  //函数内的静态局部变量,第一次访问才初始化,程序结束,自动释放。
            return &instance;
        }
    };
    

    gcc 4.0之后的编译器支持这种写法。
    C++11及以后的版本(如C++14)的多线程下,正确。
    C++11之前不能这么写。

    展开全文
  • 单例模式:意思是一个类只能实例化一个对象,且无法通过拷贝构造,赋值构造等方法构造对象。 线程安全模式 饥汉模式 懒汉模式
  • 文章目录前言单例模式(懒汉模式-双检锁、饿汉模式、静态内部类模式)-详细01 单例模式是什么?02 单例模式的好处?03 单例模式的三种模式03::01 懒汉模式03::01::01 问:为什么不在方法上加锁,而是在方法内部加锁?03::...
  • 设计一个类,只能创建一个对象(单例模式) 1 设计一个类,只能在堆上开辟空间 在正常情况下,用类实例化出的对象,都会调动它的构造函数,构造函数会在栈上申请一份空间用来存储该对象的成员变量,但是现在规定该类...
  • java多线程案例中的单线程模式——饿汉、懒汉
  • 单例模式要解决的问题 主要用于解决一个全局使用的类频发的创建和销毁的问题。单例模式下确保某一个类中只有一个实例,并且自行实例化,然后自行提供给整个系统使用。 单例的实现步骤 ...// 经典懒汉模式(用时
  • 单例模式(懒汉模式)

    2021-06-11 14:28:28
    1.特点:全局变量,整个项目只提供一个对象。 2.应用场景: a: 设备管理器,系统中可能有多个设备,但是只有一个设备管理器,用于...实现(未加锁的懒汉模式): class Singleton { public: ~Singleton(){ std::cout!" 
  • C++设计模式之单例模式讲解应用场景一、单例模式是什么?二、使用步骤1.UML图2.代码实现 应用场景 通常我们在做通讯的时候,我们跟服务器数据交互,假如每次需要通讯交互我们都创建一个实例来通讯的话,那么其实...
  • 这是两种典型的懒汉模式(防止资源泄露)的实现,但不保证线程安全 类内嵌套自定义的用于释放资源的类 #include<iostream> class Singleton { public: static Singleton* get_singleton(){ if(Singleton::...
  • 单例模式:懒汉模式

    2020-09-14 15:33:51
    所谓“懒汉式”与“饿汉式”的区别,是在与建立单例对象的时间的不同。...懒汉模式: public class Singleton2 { private volatile static Singleton2 singleton; // 5 private Singleton2() { Sys.
  • 单例模式 1、设计模式:什么是设计模式?设计模式就是针对一些...我们一步步来看懒汉模式,首先与饿汉模式的区别是:在类加载的时候不创建实例,而是在用的时候在创建实例。 我们在这里并没有直接创建实例,而是在
  • 单例设计模式:顾名思义就是某个对象永远只有一个,绝对不可以出现第二个单例模式种类:懒汉模式和饿汉模式懒汉模式:意思就是在你要使用我这个对象的时候,我判断该对象为null的时候我才创建,而不是像饿汉模式一...
  • Java 单例模式 懒汉模式 //懒汉式 多线程中不可以保证是一个对象
  • 一:饿汉模式 // 单例模式:饿汉式 public class Singleton { private static Singleton singleton=new Singleton();//饿汉式(一开始就新建对象分配内存) public Singleton(){ } public static Singleton ...
  • 单例模式
  • 饿汉模式是在类加载时便初始化,这里不做详谈,而懒汉模式则是在有人使用它的时候加载。主要针对懒汉模式对其进行不断优化。 懒汉模式 1 – 不安全:一开始是没有对象的,有人需要的时候,才会实例化。而且第一次...
  • java 单例模式(饿汉模式和懒汉模式)

    千次阅读 2021-03-15 11:29:51
    二者最主要的区别在于创建对象的时机不同: 饿汉模式是在类加载时就创建了对象实例,而懒汉模式是在使用时才创建(也就是调用获取实例对象方法时才创建) 饿汉模式不存在线程安全问题,懒汉模式存在线程安全问题 饿汉模式...
  • 懒汉模式2.1. 优缺点3. 饿汉模式4. 二者对比 1. 概述 单例模式属于创建型模式的一种,应用于保证一个类仅有一个实例的场景下,并且提供了一个访问它的全局访问点,如spring中的全局访问点BeanFactory,spring下所有...
  • 单例模式——懒汉模式

    千次阅读 2018-08-22 18:03:47
    上一篇文章讲到了单例模式的饿汉模式,这一篇来讨论一下单例模式的懒汉模式。 所谓懒汉模式,就是像一个懒汉一样,需要用到创建实例了程序再去创建实例,不需要创建实例程序就“懒得”去创建实例,这是一种时间换...
  • //由于是懒汉模式,不会立即创建实例,而是会有用到时才会创建, //为防止内存可见性问题,所以加volatile修饰,保证instance内存可见 private volatile static Singleton2 instance = null; //为防止程序猿new多...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 64,169
精华内容 25,667
关键字:

懒汉模式