zoukankan      html  css  js  c++  java
  • 实现单例模式的线程安全的类

    单例模式:是设计模式中比较简单的一种,适合于一个类只有一个实例的情况,比如窗口管理,打印缓冲池和文件系统

    单例模式特点:

    一.确保一个类只有一个实例被创建

    2.在不影响单例类的客户端的情况下允许将来有多个实例,经典的模式:懒汉式,饿汉式,登记式

    3.提供了一个对全局对象的全局访问指针

    模式:

    一.懒汉式:延迟加载,也就是说实例直到第一次用到的时候才会创建(时间来换空间),并在以后仅返回此实例

      需要用锁来保证线程的安全性 原因:多个线程可能进入判断是否已经存在实例的if语句,从而不安全

      使用double-check来保证线程安全,但是处理大量的数据的时候,该锁会成为严重的性能瓶颈

    1.静态成员实例的懒汉模式

    class Singleton
    {
    private:
        static Singleton* m_instance;   //静态成员实例 
        Singleton(){}
    public:
        static Singleton* getInstance();  //声明 
    };
    
    Singleton* Singleton::getInstance()
    {
        if(NULL == m_instance)      //第一次检查是否创建 
        {
            Lock();//借用其它类来实现,如boost,加锁 
            if(NULL == m_instance)    //再次判断是否创建 
            {
                m_instance = new Singleton;    //创建 
            }
            UnLock();   //解锁 
        }
        return m_instance;   //返回实例 
    }

    2.内部静态实例的懒汉模式

    class SingletonInside
    {
    private:
        SingletonInside(){}
    public:
        static SingletonInside* getInstance()
        {
            Lock(); // c++0x之后不用加锁 
            static SingletonInside instance;  //内部静态实例 
            UnLock(); // c++0x之后不用 
            return instance; 
        }
    };

    二.饿汉式:一开始就创建了实例,所以后仅返回此实例(空间换时间)

    由静态初始化实例保证线程安全性,因为静态实例初始化在程序开始时进入主函数之前就由主线程以单线程的方式完成了初始化,所以不必担心多线程的问题,所以要求高性能时,应使用这种模式,避免繁杂的锁争夺。

    class SingletonStatic
    {
    private:
        static const SingletonStatic *m_instance;  //声明实例 
        SingletonStatic(){}
    public:
        static SingletonStatic* getInstance()
        {
            return instance; 
        }
    };
    //注意这里不是进行创建对象,而是进行上述声明对象的初始化 ,所以必然在main之前 
    const SingletonStatic * SingletonStatic::m_instance =new SingletonStatic; 

      思考?为什么非要用 const static ?

    答案:为了更好地线程安全,因为const表示的是一旦被赋值,不能修改,static用来保证单例进入main函数之前就已经被初始化了。

    三.登记式

    登记式实际上是对于一组单例模式进行的维护,主要是在数量上的扩展,通过map我们把单例存进去,然后在使用的时候判断实例是否存在,如果不存在,则创建一个存入map中,再返回,如果存在直接返回,在数量上分又分为固定数量的和不固定数量的。

    登记类单例类为了克服饿汉式单例类以及懒汉式单例类均不可继承的缺点设计的,只是它的子类实例化只能是懒汉式的,

    缺点:(1)由于子类必须允许父类以构造函数调用产生实例,这样它的构造函数必须是公开的,这样一来就等于允许以这样的方式产生实例,而不在父类的登记中(2)父类的实例必须存在才能有子类的实例,这在有些情况下是一个浪费。

    public class RegSingleton {
     //登记薄,用来存放所有的实例
        private static Map regSingletonMap = new HashMap();
       
        //在类加载的时候添加一个实例到登记薄
        static{
         RegSingleton regSingleton = new RegSingleton();
         regSingletonMap.put(regSingleton.getClass().getName(),regSingleton);
        }
        //保护的默认构造函数
        protected RegSingleton(){
         
        }  
       
       
        public static RegSingleton getInstance(String name){
           if(name == null){
             name = "RegSingleton";
           }
    //如果没有找到实例,那就创建一个实例,加入map并返回
    if(regSingletonMap.get(name) == null){ regSingletonMap.put(name, (RegSingleton)Class.forName(name).newInstance()); } return regSingletonMap.get(name); } }
  • 相关阅读:
    听过闰年闰月,可你听过闰秒吗?
    在线学习的“后浪”:现代学习系统中的人工智能
    idea在service窗口中显示现有微服务启动类
    Intellij IDEA导入项目出现Cannot load settings from file错误
    HttpServletRequest的getRequestURL方法获取不到https协议请求问题
    新增gitignore无效的解决办法
    访问腾讯存储桶中的文件,跨域问题的解决
    线程池的创建方法推荐
    TreeMap在自定义排序时的坑
    vue.js功能学习
  • 原文地址:https://www.cnblogs.com/jijiji/p/4862103.html
Copyright © 2011-2022 走看看