博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
设计模式从入门到放弃系列:单例模式
阅读量:7282 次
发布时间:2019-06-30

本文共 3612 字,大约阅读时间需要 12 分钟。

单例模式

简介

单例模式,是一种常用的软件设计模式。在它的核心结构中只包含一个被称为单例的特殊类。通过单例模式可以保证系统中,应用该模式的一个类只有一个实例。即一个类只有一个对象实例。

特点

1、单例类只能有一个实例。

2、单例类必须自己创建自己的唯一实例。
3、单例类必须给所有其他对象提供这一实例

实现

说到代码实现,主要是3点

1.私有静态变量
2.私有化构造函数
3.静态的对象获取方法
相信看到这的时候你心里就有个答案了,看看和下面的所谓懒汉模式的代码是不是一样。

懒汉模式,线程不安全

/// /// 懒汉,线程不安全/// public class Singleton1{     private static Singleton1 _singleton = null;//私有静态变量     private Singleton1() { }//私有化构造函数     public static Singleton1 GetSingleton()//静态的对象获取方法     {          if (_singleton == null)//保证为空才创建          {               _singleton = new Singleton1();          }          return _singleton;     }}

如果这个答案和你想的一样,并一直也是这样用的,那只能说too young to simple,此方法其实有俩方面的问题,首先是线程不安全,如果同一时间,多个线程同时获取实例,则会出现获取到不同的实例,所谓的单例也就成了线程内单例,明显不对,解决办法往下看。

懒汉模式,线程安全

/// /// 懒汉,线程安全/// public class Singleton2{     private static Singleton2 _singleton = null;     private static object _lock = new object();     private Singleton2() { }     public static Singleton2 GetSingleton()     {          lock (_lock)//保证线程安全          {               if (_singleton == null)//保证为空才创建               {                    _singleton = new Singleton2();               }               return _singleton;          }     }}

话不多说,看过代码的你多半你也会说一句,加锁大法好.到这我们基本上算是实现了,但是我们看看这个锁,虽然解决了多个实例对象问题,但是该方式运行效率却很低,下一个线程想要获取对象,就必须等待上一个线程释放锁之后,才可以继续运行,但实际上对象大部分情况是已经存在了的并不需要new,因此对上个方法做了个优化。

懒汉优化模式(双检锁/双重校验锁(double-checked locking))

/// /// 懒汉优化/// public class Singleton3{     private static Singleton3 _singleton = null;     private static object _lock = new object();     private Singleton3() { }     public static Singleton3 GetSingleton()     {          if (_singleton == null)//保证对象初始化之后,线程不需要等待锁          {               lock (_lock)//保证线程安全               {                    if (_singleton == null)//保证为空才创建                    {                         _singleton = new Singleton3();                    }               }          }          return _singleton;     }}

到这我们想要的单例模式基本算ok了,码得我自己都累,想想设计模式这么多年的沉淀,就没有简单点的写法么?答案当然是肯定有的,从实现方法的命名也可以看出,除了懒汉模式,还有对应的饿汉模式,相对来说写法比较简单。

饿汉模式

/// /// 饿汉模式1/// public class Singleton4{     private static Singleton4 _singleton = null;     private Singleton4()     {     }     ///      /// 静态构造函数,由CLR调用,在使用之前被调用,而且之调用一次     ///      static Singleton4()     {          _singleton = new Singleton4();     }     public static Singleton4 GetSingleton()     {          return _singleton;     }}/// /// 饿汉模式2/// public class Singleton5{     ///      /// 静态变量:会在类型第一次使用的时候初始化,而且只初始化一次     ///      private static Singleton5 _singleton = new Singleton5();     private Singleton5()     {     }     public static Singleton5 GetSingleton()     {          return _singleton;     }  }

以上俩种方式,我个人认为是等价的,一个应用了静态变量,一个用的静态构造函数。虽然写法相对简单,不过,instance 在类装载时就实例化,虽然导致类装载的原因有很多种,在单例模式中大多数都是调用 getInstance 方法, 但是也不能确定有其他的方式(或者其他的静态方法)导致类装载,这时候初始化 instance 显然没有达到 lazy loading 的效果。嗨,有问题总得解决,看看下面。

登记模式(静态内部类)

public class Singleton6{     private static class SingletonHolder     {          internal static Singleton6 _singleton = new Singleton6();     }     private Singleton6() { }     public static Singleton6 GetSingleton()     {          return SingletonHolder._singleton;     }}

这种方式同样利用了静态变量的机制来保证初始化 instance 时只有一个线程,同时又解决了lazy loading。因为 SingletonHolder 类没有被主动使用,只有通过显式调用 getInstance 方法时,才会显式装载 SingletonHolder 类,从而实例化 instance。想象一下,如果实例化 instance 很消耗资源,所以想让它延迟加载,另外一方面,又不希望在 Singleton 类加载时就实例化,这个时候,这种方式相对来说比较实用。

综述

一般情况下,懒汉优化模式更多的是让我们从头出发,理解单例模式的运行过程和实现思路,建议使用饿汉方式(Singleton4/Singleton5)。只有在要明确实现 lazy loading 效果时,才会使用登记模式。

补充

事实上,通过反射机制是能够实例化构造方法为private的类的,那基本上会使所有的单例实现失效。所以如果拿反射来讨论单例模式,出门左转谢谢~

转载于:https://www.cnblogs.com/RenshuozZ/p/10616486.html

你可能感兴趣的文章
Canvas
查看>>
排版定位
查看>>
神经网络理论与工程实战-知识积累
查看>>
洛谷 P1198 [JSOI2008]最大数
查看>>
Anaconda使用记录
查看>>
It's only too late if you decide it is. Get busy living, or get busy dying(转)
查看>>
tomcat开发,url参数乱码.
查看>>
Flask学习【第11篇】:整合Flask中的目录结构
查看>>
mongoDB 基本crud,索引
查看>>
.NET程序员所需要注意的网站资源
查看>>
移动硬盘出现参数错误,无法访问的问题
查看>>
预处理器标识#error的目的是什么
查看>>
c3p0数据库连接池使用
查看>>
战争哲学
查看>>
【Unity3D技术文档翻译】第1.2篇 为打包 AssetBundles 准备资产
查看>>
COSBench性能测试配置--一张图说明一切
查看>>
Windows桌面共享中一些常见的抓屏技术
查看>>
python中return的用法
查看>>
转载:C# 之泛型详解
查看>>
转载:ActiveMQ的可靠性机制
查看>>