• 24、面向对象的设计模式之单例模式--基础概念及实现


    单例模式的定义如下:

      单例模式(Singleton Pattern):确保某一个类只有一个实例,而且自行实例化并向整个系统提供这个实例,这个类成为单例类,它提供全局访问的方法。单例模式是一种对象创建型模型。

    单例模式的分类:

      饿汉单例

      懒汉单例

      单线程单例

      多线程单例

    饿汉单例:

    public class EagerSingleton
    {
        // 由于在定义变量的时候实例化单例类,在类加载时就已经创建了单个对象。
        private static EagerSingleton instance = new EagerSingleton();
        private EagerSingleton()
        {
    
        }
        public static EagerSingleton GetInstance()
        {
            return instance;
        }
    }

    懒汉单例:

    //在第一次调用GetInstance()方法时实例化,在类加载并不自行实例化。这种技术叫做延迟加载(Lazy Load),就是在需要的时候在加载实例。
    //为了避免多线程调用GetInstance方法。加lock
    public class LazySingleton
    {
        private static LazySingleton instance = null;
        private LazySingleton()
        {
    
        }
        public static LazySingleton GetInstance()
        {
            if(instance == null)
            {
                new LazySingleton();
            }
            return instance;
        }
    }

    单线程单例模式:

    public class SingleThreadSingleton
    {
        private static SingleThreadSingleton instance = null;
        private SingleThreadSingleton()
        {
    
        }
    
        public static SingleThreadSingleton GetInstance()
        {
            if(instance == null)
            {
                instance = new SingleThreadSingleton();
            }
            return instance;
        }
    }

    多线程单例:

    public class MultiThreadSingleton
    {
        private static MultiThreadSingleton instance;
        private static readonly object syncRoot = new object();//静态的只读的辅助对象
        private MultiThreadSingleton()
        {
    
        }
    
        public static MultiThreadSingleton GetInstance()
        {
            lock (syncRoot) // 同一时刻枷锁的这部分程序只有一个线程进入。但是有一个问题这样会影响效率
            {
                if(instance == null)
                {
                    instance = new MultiThreadSingleton();
                }
            }
            return instance;
        }
    }

    多线程实例改良版: (volatile的作用和用法详见-C#学习——volatile关键字

    public class MultiThreadSingleton
    {
        //  volatile 保证严格意义的多线程编译器在代码编译时对指令不进行微调
        private static volatile MultiThreadSingleton instance = null;
        private static readonly object syscRoot = new object();
        private MultiThreadSingleton()
        {
    
        }
        public static MultiThreadSingleton GetInstance()
        {
            
            if(instance == null)// 多个线程调用GetInstance方法时,都可以通过第一重if(instance == null),可以提升效率
            {
                lock (syscRoot) //只有一个线程时进入
                {
                    if(instance == null) // 如果没有这层,第一个线程创建了实例,第二个线程还可以创建实例。
                    {
                        instance = new MultiThreadSingleton();
                    }
                }
            }
            return instance;
        }
    }

    静态单例模式:

    public class StaticSingleton
    {
        public static readonly StaticSingleton instance = new StaticSingleton();
        private StaticSingleton()
        {
    
        }
    }
    public class StaticSingleton
    {
        public static readonly StaticSingleton instance;
        private StaticSingleton()
        {
    
        }
    
        static StaticSingleton()
        {
            instance = new StaticSingleton();
        }
    }

    饿汉单例与懒汉单例类比较

      饿汉单例在类被加载时就将自己实例化,它的优点在于无需考虑多线程访问问题,可以保证实例的唯一性;从调用速度和反应时间角度来讲,由于单例对象一开始就得以创建,因此要优于懒汉式单例。但是无论系统在运行时是否需要使用该单例对象,由于在类加载时该对象就需要创建,因此从资源利用效率角度来讲,饿汉式单例不及懒汉式单例,而且在系统加载时由于需要创建饿汉式单例对象,加载时间可能会比较长

      懒汉式单例类在第一次使用时被创建,无需一直占用系统资源,实现了延迟加载,但是必须处理好多线程同时访问的问题,特别是当单例类作为资源控制器,在实例化时必然涉及资源初始化,而资源初始化很有可能耗费大量时间,这意味着出现多线程同时首次引用此类的几率变得较大,需要通过双重锁定机制进行控制,这将导致系统性能受到影响

    一种更好的单例实现方法

      饿汉式单例不能实现延迟加载,不管将来用不用始终占据内存;懒汉式单例类线程安全控制繁琐,而且性能受影响。可见无论是饿汉式单例还是懒汉式单例都存在这样那样的问题,有没有一种方法,能够将两种单例的缺点都克服,而将两者的优点合二为一呢?答案是:Yes!下面我们学习一种更好的被称之为Initialization Demand Holder(初始化需求持有人 loDH)的技术。

      在loDH中,我们在单例中增加了一个静态(static)内部类,在该内部类中创建单例对象,再将该单例对象通过getInstance()方法返回给外部使用,实现代码如下所示:

      

    public class Singleton
    {
        private Singleton()
        {
    
        }
        
        private static class HolderClass
        {
            public static Singleton instance = new Singleton();
        }
    
        public static Singleton GetInstance()
        {
            return HolderClass.instance;
        }
    }
    
    public class Program
    {
        public static void Main(string[] args)
        {
            Singleton s1, s2;
            s1 = Singleton.GetInstance();
            s2 = Singleton.GetInstance();
            Console.WriteLine(s1 == s2);
        }
    }

      编译并运行上述代码,运行结果为:True,即创建的对象s1和s2为同一对象。由于静态单例对象没有作为Singleton的成员变量进行直接实例化,因此类加载时不会实例化Singleton,第一次调用getInstance()时将加载内部类HolderClass,该内部中类定义了一个static类型的变量instance,此时会首先初始化这个成员变量,由C#公共运行时(Java中是Java虚拟机)来保证其线程安全性,确保该成员变量只能初始化一次。由于getInstance()方法没有任何线程锁定,因此其性能不会造成任何影响。

  • 相关阅读:
    vulcanjs 包类型
    vulcanjs schemas&& collections
    vulcanjs 核心架构概念
    vulcanjs 开源工具方便快速开发react graphql meteor 应用
    ory Oathkeeper Ecosystem
    ory Oathkeeper docker-compose 安装运行
    benthos stream nats 集成试用
    benthos 几个方便的帮助命令
    benthos 通过配置文件配置 stream 说明
    benthos 通过rest api 配置 stream 说明
  • 原文地址:https://www.cnblogs.com/sy-liu/p/13079937.html
Copyright © 2020-2023  润新知