面试官最爱问的设计模式-单例模式
为什么单例模式一直是面试官的最爱,归根结底是单例模式既简单又不简单,简单的是写个单例模式确实很简单,但是单例模式引伸出的问题可以很多很多,比如多线程、延迟加载、静态构造函数、内部类等等。
如果面试者能写出内部类实现的单例模式几乎很少,为什么要写内部类实现的单例模式,看了下面简单的介绍你就全部明白了。
1、基本概念
单例模式(Singleton)保证一个类仅有一个实例,并提供一个访问它的全局访问点。
单例模式(Singleton)也叫单态模式,是设计模式中最为简单的一种模式,甚至有些模式大师都不称其为模式,称其为一种实现技巧,因为设计模式讲究对象之间的关系的抽象,而单例模式只有自己一个对象,也因此有些设计大师并把把其称为设计模式之一。
2、常用几种形式
A、最基本的
public class Singleton { private static Singleton instance; private Singleton() { } public static Singleton GetInstance() { return instance ?? (instance = new Singleton()); } }
单例模式 ,保证一个类只有一个示例
类的自身保存唯一的实例,这个类可以保证没有其他实例被创建,并且可以提供一个访问实例的方法
B、多线程模式
public class Singleton { private static Singleton intance; private Singleton() { } private static readonly object thisLock = new object(); public static Singleton GetInstance() { lock (thisLock) { return intance ?? (new Singleton()); } } }
保证多线程环境下只有一个实例。
C、双重锁定
public class Singleton { //定义一个私有的静态全局变量来保存该类的唯一实例 private static Singleton intance; //定义一个只读静态对象,且是在程序运行时创建的 private static readonly object thisLock = new object(); /// <summary> /// 构造函数必须是私有的 /// 这样在外部便无法使用 new 来创建该类的实例 /// </summary> private Singleton() { } /// <summary> /// 定义一个全局访问点 /// 设置为静态方法 /// 则在类的外部便无需实例化就可以调用该方法 /// </summary> /// <returns></returns> public static Singleton GetInstance() { //这里可以保证只实例化一次 //即在第一次调用时实例化 //以后调用便不会再实例化 //一重锁定 intance == null if (intance == null) { lock (thisLock) { //二重锁定 intance == null //return intance ?? (new Singleton()); if (intance == null) { intance = new Singleton(); } } } return intance; } }
双重锁定不让线程每次都加锁,而是在实例未被创建的时候再加锁处理
以上ABC都是第一次引用时才将自己实例化 也称为懒汉式单例类
D、静态初始化
public sealed class Singleton { private static readonly Singleton intance = new Singleton(); private Singleton() { } public static Singleton GetInstance() { return intance; } }
D这种自己被加载时就将自己实例化称为饿汉式单例类 (多线程下是安全的)
E、登记式模式(holder内部类)
public class Singleton { //构造方法是私有的,从而避免外界利用构造方法直接创建任意多实例。 private Singleton() { } public static Singleton GetInstance() { return Holder.Intance; } //类级的内部类,也就是静态的成员式内部类,该内部类的实例与外部类的实例 //没有绑定关系,而且只有被调用到才会装载,从而实现了延迟加载 private static class Holder { //静态初始化器由JVM来保证线程安全 internal static readonly Singleton Intance = new Singleton(); } }
内部类只有在外部类被调用才加载,产生实例;不用加锁。
此模式有上述两个模式的优点,屏蔽了它们的缺点,是最好的单例模式。
3、优缺点
懒汉式单例类
优点:第一次调用才初始化,避免内存浪费
缺点:必须加锁才能保证单例,但加锁会影响效率
饿汉式单例类(静态初始化)
优点:没有加锁,执行效率会提高
缺点:类加载就实例化对象。提前占用系统资源
建议用内部类实现单例模式
4、单例模式使用场景
A、资源共享的情况下,避免由于资源操作时导致的性能或损耗,如日志文件,配置文件
B、控制资源的情况下,方便资源之间的互相通信。如线程池
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 分享 3 个 .NET 开源的文件压缩处理库,助力快速实现文件压缩解压功能!
· Ollama——大语言模型本地部署的极速利器
· DeepSeek如何颠覆传统软件测试?测试工程师会被淘汰吗?