小看--单例设计模式

    (一)单例设计描述

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

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

     --实例成员:只有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关键字的就是属于饿汉式;饿汉式:管你之前有没有(内存中),都会帮你new一个新的实例。

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

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

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

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

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

   //单例模式的应用场景补充:读取配置文件信息,读取配置文件不应该一直new一个类,应该是单例的。

       

 

      

 

   public class ConfigV1{private static object _lockObj = new object();private static ConfigV1 _instance;private static Dictionary<string,string> _configItems =new Dictionary<string, string>();private ConfigV1(){Init();Console.WriteLine($"{this.GetType().Name}被构造一次");}public static  ConfigV1 GetInstance(){if (_instance == null){lock (_lockObj){if (_instance == null){_instance=new ConfigV1();}}}return _instance;}public string  this[string item]{get{return _configItems[item];}}private  void Init(){var config=ConfigurationManager.AppSettings.AllKeys;foreach(var key in config){_configItems.Add(key,ConfigurationManager.AppSettings[key]);}}}

       github:https://github.com/gdoujkzz/DesignPattern.git

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

     

 

   

 

 

 

     

转载于:https://www.cnblogs.com/gdouzz/p/8319485.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/354215.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

selenium原理python_从python角度解析selenium原理

1、selenium工作流程2、selenium工作原理(1)客户端和服务端之间实际是通过http协议进行通信&#xff0c;服务端的接口文档可参考&#xff1a;https://github.com/SeleniumHQ/selenium/wiki/JsonWireProtocol#sessionsessionidelement(2)客户端按照服务端接口要求传入请求方式、…

Jmeter(二)Jmeter目录介绍

看过许多有关Jmeter的博客&#xff0c;算得上的收获颇丰&#xff1b;不过最牛逼的博客还是“官方文档”&#xff0c;官方文档是ApacheJmeter自己对自己产品的说明&#xff0c;论起对自己产品的理解程度&#xff0c;那肯定是自己嘛。。。因此推荐大家从Jmeter的官方文档开始学习…

使用Spring Data MongoDB和Spring Boot进行数据聚合

MongoDB聚合框架旨在对文档进行分组并将其转换为聚合结果。 聚合查询包括定义将在管道中执行的几个阶段。 如果您对有关该框架的更深入的细节感兴趣&#xff0c;那么 mongodb docs是一个很好的起点。 这篇文章的重点是编写一个用于查询mongodb的Web应用程序&#xff0c;以便从…

结合前段修改mysql表数据_jquery实现点击文字可编辑并修改保存至数据库

这个方法网上可以查到很多&#xff0c;但是好多只有点击文字编辑并保持&#xff0c;但是没有完整的代码写怎么保存到数据库。因为本人才疏学浅&#xff0c;费啦好长时间才写好把修改的内容只用一条sql语句保存到数据库&#xff0c;今天在这里和大家分享这是运行图片这是前台页面…

java 设置两个方法互斥_分享两个操作Java枚举的实用方法

1. 前言Java枚举在开发中是非常实用的。今天再来分析几个小技巧并且回答一些同学的的疑问。首先要说明的是我的枚举建立在以下的范式之中&#xff1a;枚举统一接口范式2. 如何把枚举值绑定的下拉列表这种场景非常常见&#xff0c;如果你把状态、类别等属性封装成枚举的结构&…

Spring管理的交易说明-第2部分(JPA)

在本系列的第一部分中 &#xff0c;我展示了事务如何在普通JDBC中工作 。 然后&#xff0c;我展示了Spring如何管理基于JDBC的事务。 在本系列的第二部分中&#xff0c;我将首先展示事务如何在普通的JPA中工作。 然后展示Spring如何管理基于JPA的事务。 资金转移 为了帮助说明…

CCC数字钥匙设计【BLE】--车主配对之BLE OOB配对

本文主要介绍CCC3.0采用BLE进行车主配对时&#xff0c;关于蓝牙OOB配对的内容。 首先&#xff0c;介绍下BLE Pairing的一些基础知识&#xff0c;有一些基本概念。之后&#xff0c;再着重介绍CCC规范定义的BLE OOB配对流程。 1、BLE Pairing基础知识 下面先简单介绍下BLE 5.0协…

Linux 查看内存状态

# 查看系统内存 命令&#xff1a;free 注&#xff1a;默认k单位显示注&#xff1a;-m 以MB注&#xff1a;-g以GB 单位显示total used free shared buffers cached Mem: 497 463 33 0 13 124 -/ buffe…

Altium Designer导入pcb原件之后都是绿的

转载于:https://www.cnblogs.com/chulin/p/8342041.html

在JConsole和VisualVM中查看DiagnosticCommandMBean

我已经将JConsole用作合适的通用JMX客户端已有很多年了。 该工具通常随Oracle JDK一起提供&#xff0c;并且易于使用。 在JMX交互方面&#xff0c;JConsole优于VisualVM的最大优点是JConsole带有内置的MBeans选项卡&#xff0c;而必须为VisualVM中的相同功能应用插件。 但是&am…

人人商城生成app教程_人人商城APP打包教程(APICLOUD版)

一.APP环境搭建和配置编译1.登录APICLOUD后台新建应用step1 注册账号注册apicloud 账号并登录APICLOUD控制台step2 新建应用再账户下面找到开发控制台>开发控制台>创建应用 填写应用名和说明&#xff0c;必选Native App创建Native App2 .开发工具下载安装APICLOUD开发工具…

WPF快速入门系列(2)——深入解析依赖属性

一、引言 感觉最近都颓废了&#xff0c;好久没有学习写博文了&#xff0c;出于负罪感&#xff0c;今天强烈逼迫自己开始更新WPF系列。尽管最近看到一篇WPF技术是否老矣的文章&#xff0c;但是还是不能阻止我系统学习WPF。今天继续分享WPF中一个最重要的知识点——依赖属性。 二…

圆台下料展开计算方法_怎么画 圆锥台展开图

展开全部1、 画出圆台的主视抄图(等腰梯形)袭&#xff1a;圆台的上bai下底直径为等腰梯形du的上zhi下底&#xff0c;圆台的高为等dao腰梯形的高&#xff1b;2、将等腰梯形补画成等腰三角形&#xff1b;(图中的虚线三角形即为补画部分)&#xff1b;3、以三角形的顶点为圆心&…

.31-浅析webpack源码之doResolve事件流(3)

放个流程图&#xff1a; 这里也放一下request对象内容&#xff0c;这节完事后如下(把vue-cli的package.json也复制过来了)&#xff1a; /*{ context: { issuer: , compiler: undefined },path: d:\\workspace\\doc,request: ./input.js,query: ,module: false,directory: false…

c++ 虚函数,纯虚函数的本质区别

转载博客&#xff1a;https://mp.weixin.qq.com/s?__bizMzAxNzYzMTU0Ng&amp;mid2651289202&amp;idx1&amp;sn431ffd1fae4823366a50b68aed2838d4&amp;chksm80114627b766cf31f72018ef5f1fe29591e9f6f4bd72018e7aea849342ca6f0a271fb38465ae#rd 学习C的多态性&…

云通讯短信验证码实例

1.注册登录云通讯 http://www.yuntongxun.com/user/login 2.创建应用得到应用相关信息 3.下载对应相关的Demo示例  http://www.yuntongxun.com/doc/rest/sms/3_2_2_3.html 4.send.php文件添加代码方便后续操作 session_start(); //随机验证码 $code rand(100000,999999)…

java 数组 内存_图解Java数组的内存分配

1. Java数组是静态的Java是静态语言&#xff0c;所以Java的数组也是静态的&#xff0c;即&#xff1a;数组被初始化后&#xff0c;长度不可变静态初始化&#xff1a;显式指定每个数组元素的初始值&#xff0c;系统决定数组长度String[] books new String[]{"疯狂Java讲义…

libgdx和Kotlin –类[2D平台原型]

这篇文章是libgdx和Kotlin文章的后续文章。 我已经决定开发一个简单的2D平台程序的原型&#xff08;沿着我的早期文章中的Star Assault进行介绍&#xff09;&#xff0c;但是我一直在使用和学习Kotlin&#xff0c;而不是Java。 对于本教程&#xff0c;该项目应处于上一篇文章…

spring jmx_JMX和Spring –第2部分

spring jmx这篇文章从本教程的第1部分继续。 嗨&#xff0c;在我的上一篇文章中&#xff0c;我解释了如何通过Spring设置JMX服务器以及如何通过身份验证和授权保护对它的访问。 在本文中&#xff0c;我将展示如何实现一个简单的MBean&#xff0c;该MBean允许用户在运行时更改L…

LeetCode:位运算实现加法

LeetCode&#xff1a;位运算实现加法 写在前面 位运算符 实现加法的思路 两个加数&#xff0c;比如5(101)和6(110)&#xff0c;如何不用加法就能得出两者之和呢&#xff1f; 我们知道二进制计算中&#xff0c;如果使用异或将会产生无进位的两者之和&#xff0c;而两数相与将会产…