• 设计模式——懒汉式单例类PK饿汉式单例类


    前言

       我们都知道生活中好多小软件,有的支持多IP在线,有的仅仅局限于单个IP在线。为什么这样设计,在软件开发阶段就是,有需求就是发展。这就是软件开发的一个设计模式——懒汉式单例类和饿汉式单例类。

    内容

       现在的互联网发展很迅速,人们对保护自己隐私的意识也日益提高。所以单例模式就上场了,且看:

    单例模式

    定义:

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

    解释:

      用大白话来说就是 一条路,一次只让一个过,相当于种萝卜,一个坑只能种一个萝卜。官方讲通常我们可以让一个全局变量使得一个对象被访问,但它不能防止你实例化多个对象。一个最好的方法就是,让类自身负责保存它的唯一实例。这个类可以保证没有其他实例可以被创建,并且可以他可以提供一个访问该实例的方法。

         看图:

     

    代码也灰常简单哦:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    //作者:周丽同
    //文件:单例模式
    
    namespace ConsoleApplication2
    {
        class Singleton
        {
            private static Singleton instance;
    
            private Singleton ()//构造方法让其为private,这就堵死了外界利用new创建此类实例的可能;
            {
    
            }
    
            public static Singleton GetInstance()//此方法时获得本类实例的唯一全局访问点;
            {
                if (instance ==null )//若实例不存在,则new一个新的实例,否则返回已有的实例;
                {
                    instance = new Singleton();
                }
    
                return instance;
            }
        }
    }
    
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    //作者:周丽同
    //文件:单例模式
    
    namespace ConsoleApplication2
    {
        class Program
        {
            static void Main(string[] args)
            {
                Singleton s1 = Singleton.GetInstance();
                Singleton s2 = Singleton.GetInstance();
    
                if (s1==s2 )//比较两次实例化后对象的结果是实例相同;
                {
                    Console.WriteLine("两个对象是相同的实例。");
                }
    
                Console.Read();
            }
        }
    }

    好处:

       单例模式因为Singleton类封装它的唯一实例,这样它可以严格地控制客户是怎样访问以及何时访问它。就是对唯一实例的受控访问。

    完善单例——多线程

       对于单例模式,我们只是注意到了在实例化的时候防止实例化泛滥,但是考虑细节问题,多线程的程序中,同时访问Singleton类,调用里面的GetInstance()方法,也会有可能造成创建多个实例的现象,给我防止这个,可以给进程加一把锁来处理,相当于一个屋子只能进去一个人去完成任务,第一个人进去后把门锁了,防止后面的人去屋子里面完成在该时段的同样的任务。

    见代码:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    //作者:周丽同
    //文件:多线程时的单例
    namespace 单例模式之懒汉与饿汉
    {
        class Singleton
        {
            private static Singleton instance;
            private static readonly object syncRoot = new object();
            //程序运行时创建一个静态只读的进程辅助对象;
            private Singleton ()
            {
    
            }
    
            public static Singleton GetInstance()
            {
                lock (syncRoot )//在同一个时刻加了锁的那部分程序只有一个线程可以进入;
                {
                    if (instance ==null )
                    {
                        instance =new Singleton ();
                    }
                }
    
                return instance;
            }
        }
    }

       这里解释一下,Lock是确保当一个线程位于代码的临界区时,另一个线程不进入临界区。如果其他线程试图进入锁定的代码,则它将一直等待(即被阻止),直到该对象被释放。由于有了 lock,就保证了多线程下同上访问也不会造成多实例的生成。

       多线程虽然解决了保证实例化一个。但是对于加锁的方式上不管有没有实例化对象都是先加了锁,这样看起来未免有点不合理。双重锁定解决了这种情况。

    完善单例——双重锁定

       它先是判断实例是否存在,不存在再枷锁处理。这样我们不用让线程每次都加锁,而只是在实例未被创建的时候再加锁处理,同时这样也能保证多线程的安全。这就是我们所说的Double-Check Locking。至于为什么判断Instance是否为空两次,第一次是判断是否有加锁的毕业,第二次是针对第二次以后进来的执行者是否执行实例化的判断。

    见代码:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    //作者:周丽同
    //文件:双重锁定
    
    namespace 双重锁定
    {
        class Singleton
        {
            private static Singleton instance;
            private static readonly object syncRoot = new object();
            private Singleton()
            {
    
            }
    
            public static Singleton GetInstance()
            {
                if (instance ==null )//先判断实例是否存在,不存在再加锁处理;
                {
                    lock (syncRoot )
                    {   
                        //当instance不存在的情况下,当instance为 null并且同时有两个线程调用GetInstance()方法时;
                        //都可以通过第一重instance==null的判断。然后由于lock机制,这两个线程则只有一个进入,另一
                        //个在外排队等候。等另一个出来以后,另一个才能进入,如果没有第二重的instance==null,还是
                        //可以重新创建实例的。没有达到单例的目的。
                        if  (instance ==null )
                        {
                            instance = new Singleton();
                        }
                    }
                }
    
                return instance;
            }
        }
    }

    静态初始化

       C#与公共语言运行库也提供了一种“静态初始化”方法,这种方法不需要开发人员显式地编写线程安全代码,即可解决多线程环境下它是不安全的问题。

    见代码:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    //作者:周丽同
    //文件:静态初始化
    
    namespace 静态初始化
    {
        public sealed   class Singleton//防止发生派生,而派生可能会增加实例;
        {
            //在第一次引用类的任何成员时创建实例。公共语言运行库负责处理变量初始化;
            private static readonly Singleton instance = new Singleton();
            private Singleton ()
            {
    
            }
    
            public static Singleton GetInstance()
            {
                return instance;
            }
        }
    }

       这个也实现了全局访问和实例化控制,公共静态属性访问实例提供了一个全局访问点。不同之处在于它利用公共语言运行库来初始化变量。构造方法和前面一样都是私有的,不能再类本身以外实例化Singleton类;其中instance变量标记为readonly(只读),表示只能在静态初始化期间或在类构造函数中分配变量。

    总结

       静态初始化的方式是在自己加载的时候就将自己实例化,需要提前占用资源,所以被形象的称之为饿汉式单例类;原先的单例模式处理方式要在第一次被引用时,才会将自己实例化,面临着多线程访问的安全性问题,需要做双重锁定这样的处理才可以保证安全,所以为懒汉式单例类。本人菜鸟一枚,如果不合适的地方,望大神斧正。

    1、对比着学习更加容易理解知识。

    2、永远不要相信一件东西可以近乎完美,只要发现总有更好的。

    3、多做总结,多多回顾。


    最后的最后,感谢您的宝贵时间~~~

  • 相关阅读:
    河南省第十届ACM省赛G:Plumbing the depth of lake
    南洋理工oj 题目92 图像有用区域
    初学欧拉图,知识总结,后续增加
    初学并查集知识总结后续增加
    南阳oj 题目42 一笔画问题
    南阳oj 题目 90 整数划分
    南阳oj题目20吝啬的国度 菜鸟的进阶之路
    南阳oj 题目21 三个水杯
    UVA-540 Team Queue
    HDU-1596 find the safest road
  • 原文地址:https://www.cnblogs.com/zhoulitong/p/6412438.html
Copyright © 2020-2023  润新知