C#单例模式(Singleton Pattern)详解
作者:SuagrMatl 发布时间:2021-12-30 05:55:03
(新手写博客,主要是对自己学习的归纳总结。会对很多小细节详解。)
单例模式的定义:
确保一个类只有一个实例,并提供一个全局访问点。
首先实例大家应该都明白就是类生成对象的过程简单的就是String s=new String(),则s就是个实例。
Q:如何只生成一个实例?
A:1)首先必须将构造函数变为私有从而防止其他类实例化,并且只能有一个构造函数。因为系统会默认一个无参构造函数,而且默认public访问修饰符。 所以必须写一个私有无参让默认无效。(通常单例模式都是不带形参的)
2)在该类中声明一个自己本身的静态实例,然后通过静态方法返回。
Q:如何提供一个全局访问点?
A:在类中创建一个公共并且静态的属性。(因为静态方法是类中的一个成员方法,属于整个类,即不用创建任何对象也可以直接调用。单例模式是不允许其他类实例的。)
代码:
分为两种模式:
1.LAZY模式
就是延迟加载, 设计模式是为了避免一些无谓的性能开销而提出来的,所谓延迟加载就是当在真正需要数据(读取属性值)的时候,才真正执行数据加载操作.有效使用它可以大大提高系统性能。
2.饿汉模式
与LAZY模式相反 ,加载时会将自己实例化。起来最容易的单例模式。
分析代码1:(经典)
// 不要用这种方式
public sealed class Singleton
{
private static Singleton instance=null;//声明自己本身的静态实例
private Singleton(){}//私有构造
public static Singleton Instance() //提供全局访问点
{
if (instance==null)//实例不存在则创建
{
instance = new Singleton();
}
return instance;
}
}
该代码仅供理解,单例模式的定义。
问题:该方法是非线程安全的,当有两个线程同时进入时,如果instance为null则都会创建实例。实际上,在测试以前,实例就已经有可能被创建了,但是内存模型不能保证这个实例能被其他的线程看到。
下面我们优化改进
分析代码2:(非安全线程)
public sealed class Singleton
{
private static Singleton instance = null;
private static readonly object padlock = new object();//定义一个标识确保线程同步
Singleton(){}
public static Singleton Instance()
{
lock (padlock)//线程到达时加锁 运行完之后解锁 当遇到加锁线程就会挂起等待解锁
{
if (instance == null)
{
instance = new Singleton();
}
return instance;
}
}
}
以上解决了多线程问题。
问题:性能上来说,锁变成了每次都必须的当这个实例被响应的时候。此时完全没必要对线程辅助对象加锁之后再去判断,所以上面的实现方式增加了额外的开销。
下面我们进行优化改进:
代码分析3:(双重锁定)
public sealed class Singleton
{
private static Singleton instance = null;
private static readonly object padlock = new object();
Singleton(){}
public static Singleton Instance
{
get
{
if (instance == null)//外层的if语句块,这使得每个线程欲获取实例时不必每次都得加锁,因为只有实例为空时(即需要创建一个实例),才需加锁创建
{
lock (padlock)
{
if (instance == null)
{
instance = new Singleton();
}
}
}
return instance;
}
}
}
这种“双重检查锁定”理论上是完美的
问题是:并不能保证它会在单处理器或多处理器计算机上顺利运行。(反正就是有问题吧 之后再研读一下 看看具体是怎么回事)
代码分析4:(不完全LAZY)
public sealed class Singleton
{
private static readonly Singleton instance = new Singleton();
// 显示的static 构造函数
//静态构造函数抑制了beforefieldinit 特性(访问成员之前就执行静态函数)
static Singleton(){}
private Singleton(){}
public static Singleton Instance
{
get
{
return instance;
}
}
}
不完全LAZY模式(通过抑制beforefildinit特性并不能起到太大的效果)
代码分析5:(完全LAZY)
public sealed class Singleton
{
private Singleton(){}
public static Singleton Instance { get { return Nested.instance; }}
//嵌套类
private class Nested
{
//抑制beforefieldinit特性
static Nested(){}
internal static readonly Singleton instance = new Singleton();
}
}
这里使用了嵌套类(嵌套类型是LAZY加载的,也就是说嵌套类型在使用他时才会初始化)
代码分析6:(Lazy<T>)
public sealed class Singleton
{
//使用.NET4 Lazy<T>
private static readonly Lazy<Singleton> lazy =new Lazy<Singleton>(() => new Singleton());
public static Singleton Instance { get { return lazy.Value; } }
private Singleton() {}
}
Lazy<T> 对象初始化默认是线程安全的,在多线程环境下,第一个访问 Lazy<T> 对象的 Value 属性的线程将初始化 Lazy<T> 对象,以后访问的线程都将使用第一次初始化的数据。
以上全部是LAZY模式,现在了解下饿汉模式
代码分析7:
public sealed class Singleton
{
private static readonly Singleton instance=new Singleton();//直接实例化
private Singleton(){}
public static Singleton Instance()
{
return instance;
}
}
在这种模式下,无需自己解决线程安全性问题,CLR会给我们解决。由此可以看到这个类被加载时,会自动实例化这个类,而不用在第一次调用Instance()后才实例化出唯一的单例对象。
为了优化系统当然还是选择优化模式。LAZY模式最好的应该是使用Lazy<T>简短安全。
以上都是我在博客园对单例模式学习的总结。今后会补充一些具体的项目中的案例让和我一样的新手更容易吸收理解最终达到举一反三。这里重点参考了这里的文章,希望大家有指教的地方多多提点。感谢。
来源:http://www.cnblogs.com/Jeese/p/7428220.html


猜你喜欢
- 使用filter()取出自己所需数据java8的filter()方法是取出自己所需的数据,返回满足条件里的数据person.javapack
- Android图片的处理工具类BitmapUtils,供大家参考,具体内容如下项目中经常会用到图片,所以在这先简单的总结一下。闲言少叙,上代
- 1.值类型值类型包括:数值类型,结构体,bool型,用户定义的结构体,枚举,可空类型。值类型的变量直接存储数据,分配在托管栈中。变量会在创建
- 昨天遇到了点问题解决浪费了一些时间(导致更新内容较少)回顾下问题项目出现Unable to import maven project: Se
- java超市管理系统 1.0(含源文件,后续会继续优化~)前言一个月零零散散的时间学习了java,通过这次“超市管理系统”的练习,希望可以给
- 写在前面从Java 1.0开始,引入java.io包;到Java 1.4再扩展了java.nio包;再到java 1.7又添加了新的流类,使
- Java的Arrays类中有一个sort()方法,该方法是Arrays类的静态方法,在需要对数组进行排序时,非常的好用。但是sort()的参
- Kotlin 面向对象这几天一直在准备考试,实在没有时间,已经过去了这么久,终于要到面向对象了!先看看Kotlin中的类长什么样吧.可以看到
- 本文实例为大家分享了Android实现掷骰子效果的具体代码,供大家参考,具体内容如下利用handler接受子线程的消息完成骰子点数的不断更替
- 先明确几个概念的区别: padding margin都是边距的含义,关键问题得明白是什么相对什么的边距. padding是控件的内容相对控件
- Google在Android 4.4版本加入了半透明的界面样式,在Android 5.0的时候推出了Material Design的概念。这
- <%@ page language="java" contentType="text/html; cha
- 本文实例为大家分享了Android Service实现自动更换手机壁纸的具体代码,供大家参考,具体内容如下先看下效果:使用界面:划重点,使用
- 在开始之前,我先卖个关子提一个问题:假设我们有一个Movie类,这个类有三个成员变量分别是starred(是否收藏), title(电影名称
- 本文实例为大家分享了C#使用Aforge调用摄像头拍照的具体代码,供大家参考,具体内容如下一、新建一个Winform项目二、使用Nuget添
- 1、 定义头和根元素部署描述符文件就像所有XML文件一样,必须以一个XML头开始。这个头声明可以使用的XML版本并给出文件的字符编码。DOC
- OAuth2简介OAuth 是一个开放标准,该标准允许用户让第三方应用访问该用户在某一网站上存储的私密资源(如头像、照片、视频等),而在这个
- 在Java项目开发中,Maven是非常重要的构建工具之一,它可以帮助我们管理项目的依赖、构建和发布。本文将通过以下两个方面来介绍Maven打
- 看到题目后,分析了下, 10的阶乘就已经很大了。计算出来再得到这个末尾的0的个数,完全不现实,即使实现了也是很麻烦的。后来想某个数的阶乘中乘
- 前言一大早还在北京拥挤的地铁里,我的CTO闫哥在微信里给我发了一条信息:Android Studio 3.0发布了。为什么会这么关注Andr