小看--单例设计模式

(一)单例设计描述

只要了解过设计模式的同学都会知道:单例设计模式,大家都知道单例设计模式是一种创建行的设计模式。既然是创建型,那么先来讲讲,对象的创建的过程吧。

--静态成员:静态成员在程序加载的时候,就会加载进内存。

--实例成员:只有new的时候才有实例成员。1、为实例的数据字段分配内存,然后初始化对象的附加字段(类型指针和同步索引块),最后调用类型的实例构造器来设置对象的初始化状态。

单例模式:一般用在一个类的创建对象很消耗资源,消耗时间,并且系统要保证只有一个对象的时候。一句话,对象的创建并不是很耗时间,不要刻意去套用单例模式,单例模式必须是在单例的时候,才单例。

(二) 单例模式的演变

下面我们来模拟实际情况

 public class Singleton {
        /// <summary>
        /// 对象会持有资源
        /// </summary>
        private List<string> _connList=new List<string>()
        {
            "测试数据库连接","测试数据库连接2","测试数据库连接3","测试数据库连接4"
        };

        public Singleton()
        {
            long lResult = 0;
            for (int i = 0; i < 100000; i++){
                lResult += i;
            }
            Thread.Sleep(1000);
            Console.WriteLine("{0}被构造一次",this.GetType().Name);
        }

        public void Show()
        {
            Console.WriteLine("调用了Show");
        }

    }

这个类的创建需要耗费很多资源,里面有个Show方法。

那么接下来,实际中,我们可能有十个地方要用到这个类里面的Show方法,我们的做法是这样的

  //那么接下来,我们这里要调用十次Show方法
            for (var i = 0; i < 10; i++) {
                var singletonObj = new Singleton();
                singletonObj.Show();
            }

这里每次调用一次,都需要耗费很多资源和时间,这里可能有些同学就会说,那我把这个singletonObj=new Singleton()提取出来,放到最外面来。

那行,按照我们需要,我们把var singletonObj=new Singletone()放到外面,如下所示

貌似这样就解决了我们的问题,但是各位你们想一想,我们一个系统是有多个人开发的,A这里这样做,B可能不知道这里有这个声明,那他可能就还是一样去New Singleton,还是导致我们系统中,存在大量这个对象。

我们应该要如何解决这个问题呢? 如何保证这个对象在整个系统只被创建一次呢?

单例模式--单线程

从上面的问题,我们也可以看出因为谁都可以在New Singleton,所以导致了这个问题。那按照这个想法,那我们就想啦,那就把构造函数私有化呗,私有化完了之后,我们应该还要提供一个方法或者啥的,给外面调用(也只能是静态的成员),构造函数私有化了,外面是不可以New了的

那就按照,刚刚的说法,我们来进行一次改进

public class Singleton {
        /// <summary>
        /// 对象会持有资源
        /// </summary>
        private List<string> _connList=new List<string>()
        {
            "测试数据库连接","测试数据库连接2","测试数据库连接3","测试数据库连接4"
        };

        private Singleton(){
            long lResult = 0;
            for (int i = 0; i < 100000; i++){
                lResult += i;
            }
            Thread.Sleep(1000);
            Console.WriteLine("{0}被构造一次",this.GetType().Name);
        }

        public static Singleton CreateInstance(){
            return new Singleton();
        }

        public void Show()
        {
            Console.WriteLine("调用了Show");
        }

    }

按照我们上面这个写法,把构造函数私有化了,然后在静态方法里面New Singletone();

调用结果如下:

 for (var i = 0; i < 10; i++) {
                var singletonObj = Singleton.CreateInstance();
                singletonObj.Show();
 }  //写进里面去了,是为了模拟有十个不同的开发,再调用

那结果,还是没有达到我们想要的,那现在问题就是,对象没有重用,因为我们每次new,导致了对象没有做到重用,那就让对象进行重用呗。最简单的方法,就是给一个静态的字段(为啥静态呢,因为我们那边方法是静态的),然后做一个判断,如果对象为空,那么我们就创建,如果不为空,就不用创建了,如下所示。

我们在原来的基础上,做了如上图的改进。结果如下,

我们想要的结果实现了,多次调用的时候,做了重用对象,只构造了一次。本来想着单例模式就这样结束了,编程世界里面,我们总是要考虑一下,多线程的情况(刚刚我们的情况是单线程的)

单例模式--多线程

这个是用Task.Run()开启了也给多线程的异步调用

            for (var i = 0; i < 10; i++){
                Task.Run(()=>{
                    var singletonObj = Singleton.CreateInstance();
                    singletonObj.Show();
                });
            }
            Thread.Sleep(5000);

通过上面的结果,我们可以看出,我们的之前的做法,在多线程环境还是会调用多次。

有些同学就会说用lock锁啦,行,我们就给他加上一把锁。

public class Singleton {
        /// <summary>
        /// 对象会持有资源
        /// </summary>
        private List<string> _connList=new List<string>()
        {
            "测试数据库连接","测试数据库连接2","测试数据库连接3","测试数据库连接4"
        };

        private static Singleton singletonObj = null;
        private static readonly object singleTonObjLock = new object();  //加锁,之后这里为啥要用readonly,大家可以找

        private Singleton(){
            long lResult = 0;
            for (int i = 0; i < 100000; i++){
                lResult += i;
            }
            Thread.Sleep(1000);
            Console.WriteLine("{0}被构造一次",this.GetType().Name);
            Console.WriteLine($"线程{Thread.CurrentThread.ManagedThreadId}调用一次");
        }

        public static Singleton CreateInstance()
        {
            lock (singleTonObjLock) //很多同学都说用lock this,this肯定是不行的,因为lock是lock引用的,如果这个this的引用改变了...
            {
                if (singletonObj == null)
                {
                    singletonObj = new Singleton();
                }
            }
            return singletonObj;
        }

        public void Show()
        {
            Console.WriteLine("调用了Show");
        }

    }

看我们给他加完锁的时候效果。

嗯,实现了我们想要的效果了,说明我们加锁是有效果的。到了这个时候,大家可能觉得一个单例模式应该就快结束了,那么我们再来看看这种情况。

单例模式--多线程(双if+lock)

通过上面的介绍,我们理解了单例模式的演变过程,也对单例模式,多线程有了更加深刻的印象。

(三)单例模式其他实现

就像我们一开始说的那样,单例模式,其实一个进程内,在多线程环境下,如何保证只有一个对象,这就是单例。也可以从这个定义看出,我们可以通过静态的构造函数来实现一个单例模式。

静态构造函数,是由CLR保证的,有且只会加载一次。

其他很多方法实现,都是利用static关键字的背后原因,在第一次使用类型之前被调用,且只会被调用一次。

(四)懒汉式,饿汉式

懒汉,就是说这个人很懒,需要用的时候,才构建。双if+lock这种就属于懒汉式。

饿汉:就是调用我这个类型,就会帮你创建好;管你用不用,我都会帮你创建;就是饿了吗,我后面介绍的利用static关键字的就是属于饿汉式;

(五)单例模式的使用场景

单例:必须单例才单例,反正没必要。单例模式实现都有性能,损失,静态方法。

单例:会把对象常驻内存,静态的。

单例的使用,多个人操作可能会对你影响,因为都是对同一份引用进行修改。

一般用在数据库连接,打印机,远程服务调用,等等这些大对象身上。

谢谢你阅读我的博客,如果有收获,请点一个赞(推荐)

原文地址:https://www.cnblogs.com/gdouzz/p/8319485.html

时间: 2024-10-12 00:00:11

小看--单例设计模式的相关文章

单例设计模式

一:单例设计模式的定义 单例设计模式,顾名思义,就是在整个程序运行过程中,只向外界提供一个对象,这样做可以避免资源的浪费,例如 我们打开回收站或者ppt时,只会启动一个窗口. 单例模式的java实现: 1:饿汉式 1 /** 2 * 3 */ 4 package com.hlcui.singleton; 5 6 /** 7 * @author Administrator 饿汉式单例类 8 */ 9 public class SingletonDemo { 10 // 1:内部创建一个对象 11

iOS 中的单例设计模式

单例设计模式:在它的核心结构中只包含一个被称为单例类的特殊类.例如文件管理中的NSUserDefault,应用程序中的UIApplication,整个应用程序就这一个单例类,负责应用程序的一些操作,单例在那个文件下都能取得到. 通过单例设计模式可以保证系统中一个类只有一个实例而且该实例易于外界访问,从而方便对实例个数的控制并节省系统资源.如果希望在系统中某个类的对象只能存在一个,单例模式是最好的选择. 下面来点实在的,创建单例代码上 方法1:基于线程安全创建一个单例 .h做一下声明 + (id)

设计模式之单例设计模式

一.何为单例设计模式 单例模式,顾名思义就是单个实例,程序中某个类只有一个实例存在.通常实在需要共享某个资源避免资源损耗的情况下使用到的. 二.单例设计模式的代码实现 一说到单例模式的概念,我们首先会想到下面的这种的写法 public class SingleInstance { private static SingleInstance singleInstance; /** * 单例模式 * @return */ public static SingleInstance getSingleI

设计模式整理_单例设计模式

单例设计模式,它确保一个类只有一个实例,并提供一个全局访问点. 由于单例设计模式对应的类只能创建一个对象,因此它所对应的方法必须是static(不是static只有创建对象才能调用). 以下是单例模式的一个经典实现:采用了延迟加载对象的例子. public class Single1 { private static Single1 single; //利用一个静态变量来记录Single1的唯一实例,这里没有直接声明,采用了延迟加载模式. private Single1(){} //把构造器声明

【学习笔记】单例设计模式笔记

单例设计模式是常见的设计模式之一.通过单例实现所需求类在系统中只存在唯一一个实例. 单例设计模式分两种:懒汉单例设计模式和饿汉单例设计模式,两者设计思路一致,实现有微小不同. 实现代码: 1 public class HungryMan { 2 3 private HungryMan(){};//私有的构造方法保证HungryMan类无法在外部使用构造方法实例化 4 private static final HungryMan hungryMan=new HungryMan();//在类内定义一

IOS开发之单例设计模式

本文将从四个方面对IOS开发中的单例设计模式进行讲解: 一.什么是单例设计模式 二.我们为什么要用单例设计模式 三.单例设计模式的基本用法 四.自定义单例设计模式代码的封装 一.什么是单例设计模式 所谓单例,即是单个的实例化对象,保证一个类有且仅有一个实例.通常情况下,当我们对一个类实例化时(如:alloc.new等),并不能保证每次实例化的对象是唯一的实例.那么为了保证该类可在多次实例化的过程中保证内存地址不变,就需要引入单例设计模式. 二.我们为什么要用单例设计模式 1.Singleton

Java——单例设计模式

设计模式:解决某一类问题最行之有效的方法.Java中23种设计模式:单例设计模式:解决一个类在内存中只存在一个对象. 想要保证对象唯一.1,为了避免其他程序过多建立该类对象.先禁止其他程序建立该类对象2,还为了让其他程序可以访问到该类对象,只好在本类中,自定义一个对象.3,为了方便其他程序对自定义对象的访问,可以对外提供一些访问方式 这三部怎么用代码体现呢?1,将构造函数私有化.2,在类中创建一个本类对象.3,提供一个方法可以获取到该类对象. 对于事物该怎么描述,还怎么描述.当需要将该事物的对象

OC中的单例设计模式及单例的宏抽取

1 // 在一个对象需要重复使用,并且很频繁时,可以对对象使用单例设计模式 2 // 单例的设计其实就是多alloc内部的allocWithZone下手,重写该方法 3 4 #pragma Person.h文件 5 6 #import <Foundation/Foundation.h> 7 @interface Person : NSObject <NSCopying,NSMutableCopying> 8 + (instancetype)sharePerson; // 给类提供一

微信 使用单例设计模式 提供AccessToken 和Jsapi_ticket缓存支持

上一篇 是使用ecache 做的缓存, 有些简单的微信项目并不需要这么复杂,So就想到单例设计模式  首先,我们先定义一个单例对象 import java.util.HashMap; import java.util.Map; /**  *   * @author wangiegie  * @date 2015年9月29日下午8:13:06  * @description  */ public class Singleton { //缓存accessToken 的Map  ,map中包含 一个a