单例设计模式

article/2025/11/6 10:02:37

一.何为单例设计模式

如其名字,单例设计模式就是指的是一个类中只允许存在一个对象实例。
在java中,我们存在两种创建单例模式的思路:饿汉式和懒汉式

①饿汉式:在创建类时直接创建对象实例

public class SingleHungryMan {//建立类变量private static SingleHungryMan singleHungryMan=new SingleHungryMan();//定义私有构造方法,避免其他类调用private SingleHungryMan(){}//创建获取类对象的方法public static SingleHungryMan getInstance(){return singleHungryMan;}}

②懒汉式:在需要获取对象实例时再去创建对象实例,效率略高

public class SingleLazyMan {private static  SingleLazyMan singleLazyMan=null;//定义私有构造方法private SingleLazyMan(){}//构造获取方法public static SingleLazyMan getInstance() {if(singleLazyMan==null){singleLazyMan=new SingleLazyMan();}return singleLazyMan;                  }
}

在单线程情况下两种单例设计模式都不需要考虑线程安全问题,但是一旦到多线程情况下,懒汉式的单例设计模式存在线程安全问题,而饿汉式是在创建类之初就把实例对象创建好了,因此在多线程环境下仍然是线程安全的,我们通过下图去解析其问题:

我们进行测试,发现确实存在问题:

这种问题是多线程情况下常见的问题:不满足原子性,这种情况下我们如何解决该问题呢?

最直观的解决措施就是上锁,保持其原子性

public class LazyMan {//懒汉式单例对象//创建单例对象//使用volatile修饰,禁止指令重排序
private static volatile LazyMan lazyMan;
//私有化构造方法private  LazyMan(){}//创建实例对象public static LazyMan getLazyMan(){synchronized (LazyMan.class){//判断是否为空,为空则创建if(lazyMan==null) {lazyMan = new LazyMan();}}return lazyMan;}
}

上锁之后,问题得到了解决,但是上锁之后我们又面临了一个问题:效率问题,如果我们创建了多个线程,但是当一个线程已经创建了对象,其他线程也就不需要再进行上锁判断(因为已经创建了对象,不需要考虑线程安全问题),但是上锁操作事实上是一个很降低效率的问题,我们再次对代码进行优化

public class LazyMan {//懒汉式单例对象//创建单例对象//使用volatile修饰,禁止指令重排序
private static volatile LazyMan lazyMan;
//私有化构造方法private  LazyMan(){}//创建实例对象public static LazyMan getLazyMan(){//判断是否为空,为空则创建if(lazyMan==null) {synchronized (LazyMan.class){lazyMan = new LazyMan();}}return lazyMan;}
}

但是进行这种优化后,测试结果如下:

我们发现创建的并不是一个单例对象,分析其结果:说到底还是原子性的问题:线程2在线程1判断单例对象为空对象之后,在创建实例对象之前也进行了非空校验,这样下来,即使线程1已经创建了对象,线程2由于已经完成了非空校验,因此还会创建一个对象来覆盖线程1创建的对象,因此创建了第二个对象。因此我们需要在synchronized之内在多加一个是否仍然为空对象的校验
public class LazyMan {//懒汉式单例对象//创建单例对象//使用volatile修饰,禁止指令重排序
private static volatile LazyMan lazyMan;
//私有化构造方法private  LazyMan(){}//创建实例对象public static LazyMan getLazyMan(){//判断是否为空,为空则创建if(lazyMan==null) {synchronized (LazyMan.class){//第二次在synchronized之下判断是否为空if(lazyMan==null){lazyMan = new LazyMan();}}}return lazyMan;}
}

此时我们发现创建的对象是同一个单例对象

通过上述操作,我们已经将第一个问题高效的解决了,但是仍然存在第二个问题:

我们在进行创建对象的时候

一般分为三步

①开辟内存空间

②初始化对象

③将内存首地址赋给对象引用

①和③必须按照顺序执行,但是②和③却没有严格的执行顺序,所以②和③可能被编译器进行指令重排序,一旦②和③执行顺序调反,问题就出现了,虽然我们获得了一个内存引用,但是这个对象还没有进行初始化,我们后续操作进行引用的也就是一个无效对象。为了避免该问题的产生,我们应该禁止指令重排序,那么就应该用volatile修饰变量,我们需要说明的是:使用volatile能够避免很多我们无法考虑的线程安全问题。

结果仍然是正确的:

单例模式常见的应用场景

日志系统:在应用程序中,通常只需要一个日志系统,以避免在多个地方创建多个日志对象,并降低资源消耗。

数据库连接池:在应用程序中,数据库连接池是一个非常重要的资源,单例模式可以确保在应用程序中只有一个数据库连接池实例,避免资源浪费。

配置文件管理器:在应用程序中,通常只需要一个配置文件管理器来管理应用程序的配置文件,单例模式可以确保在整个应用程序中只有一个配置文件管理器实例。


http://chatgpt.dhexx.cn/article/tZcIJmB8.shtml

相关文章

设计模式在程序中的使用

OO设计的主要目的,在于分割责任,将每个模块的责任降低到合理的程度,并对各个模块进行封装以及降低两个模块之间的耦合度,达到修改一处不影响另外一处的目的。 这个原则其实并不仅仅局限于OO设计,只是OO设计提供了更好…

设计模式之命令模式

命令模式 命令模式的定义非命令模式实现:命令模式的实现: 命令模式的定义 说实话这个模式挺令人纠结的,但从这个模式的定义上来看,有点让人摸不到什么头脑,而且查看资料以后会发现还是有点稀里糊涂的,说懂…

《C++ 设计模式》

作者: 一去、二三里 个人微信号: iwaleon 微信公众号: 高效程序员 设计模式(Design Pattern)代表了最佳的实践,在面向对象的编程中被很多老鸟们反复使用。使用设计模式有很多好处: 可重用代码保…

设计模式课程设计

文章目录 题目要求: 具体作业如下:一、设计思路二、所用模式介绍1.简单工厂模式2.装饰模式3.观察者模式 具体实现过程程序分为三个部分: PS.代码写的比较敷衍,主要是应付作业用,请大家自行斟酌抄袭 又到了一年两度的课程设计时间&…

23种设计模式总结

一、什么是设计模式 设计模式(Design pattern)是一套被反复使用、多数人知晓的、经过分类编目的、代码设计经验的总结。使用设计模式是为了可重用代码、让代码更容易被他人理解、保证代码可靠性。 毫无疑问,设计模式于己于他人于系统都是多赢…

设计模式之——桥接模式

设计模式: 前辈们对代码开发经验的总结,是解决特定问题的一系列套路。它不是语法规定。而是一套用来提高代码可复用性、可维护性、可读性、稳健性、以及安全性的解决方案 设计模式的本质是面向对象设计原则的实际运用,是对类的封装性、继承性…

面向对象程序设计

之前复习面向对象的时候整理的,丢出来一起分享一下。因为复习得很赶,只是大致的整理,且大部分图片来自老师的ppt,可能不是很准确。如果要详细了解其中的某个知识点请另外搜索。 但是老师不讲武德啊,明明提纲给了不按提…

MVC设计模式

MVC的全名是Model View Controller,是模型(Model)-视图(view)-控制器(controller)的缩写,是一种设计模式。它是用一种业务逻辑、数据与界面显示分离的方法来组织代码,将众多的业务逻辑聚集到一个部件里面,在…

设计模式考题复习

一.定义 设计模式六大基本原则: 单一职责原则:一个类或者一个方法只负责一项职责,尽量做到类的只有一个行为原因引起变化;里氏替换原则:能出现子类的地方都应该可以允许父类出现,也就是子类可以扩展父类的…

一文带你通俗理解23种软件设计模式(推荐收藏,适合小白学习,附带C++例程完整源码)

作者:翟天保Steven 版权声明:著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处 一、设计模式是什么? 设计模式是为了解决在软件开发过程中遇到的某些问题而形成的思想。同一场景有多种设计模式可以应…

设计模式之策略模式详解

设计模式之策略模式详解 概述 先看下面的图片,我们去旅游选择出行模式有很多种,可以骑自行车、可以坐汽车、可以坐火车、可以坐飞机。 作为一个程序猿,开发需要选择一款开发工具,当然可以进行代码开发的工具有很多&#xff0c…

设计模式——桥接模式

定义 桥接模式(Bridge Pattern),也叫做桥梁模式,结构型设计模式的一种,这个模式相对来说有些难理解。桥接,顾名思义,就是用来连接两个部分,为被分离了的抽象部分和实现部分搭桥。 …

设计模式23模式介绍

🏆作者简介:哪吒,CSDN2022博客之星Top1、CSDN2021博客之星Top2、多届新星计划导师✌、博客专家💪 ,专注Java硬核干货分享,立志做到Java赛道全网Top N。 🏆本文收录于,Java基础教程系…

程序设计模式23+1种定义+UML图(有部分分析和联用)

程序设计模式这门课已经学完了,复习的时候做了一个这样的汇总,希望可以给后来学习这门课的同学一些帮助。 设计模式的分类 根据目的(模式是用来做什么的)可分为创建型(Creational),结构型(Structural)和行为型(Behavio…

程序员必备的21种“设计模式之道”!

设计模式是一套被反复使用的、多数人知晓的、经过分类编目的、代码设计经验的总结。使用设计模式的目的就是为了重用代码、让代码更容易被他人理解、保证代码可靠性。欢迎小伙伴们收藏关注,持续分享更多优质干货! 设计模式之道 何为设计模式&#xff1f…

Microsoft Office Visio 缺失安装文件的解决方法(附viso安装密钥)

工作环境(蓝色粗体字为特别注意内容) 1,软件环境:Windows 7、Microsoft Office Visio Professional 2007、Microsoft Office Enterprise2007 2,参考文献:https://zhidao.baidu.com/question/1669305667489578747.html 最近在写文…

Microsoft visio 2019 professional 安装

Visio 2019 pro,全程关闭防火墙,运行文件采用管理员运行 Visio 2019 pro 下载jihuo汉化 Visio 2019 pro 下载 从下方链接下载 链接:https://pan.baidu.com/s/1OQXUfOItLJhbKsDf_u3pEQ 提取码:1234 里面包含: 点击V…

Oracle高水位线 HWM降低技巧

作者:IT邦德 中国DBA联盟(ACDU)成员,目前从事DBA及程序编程 (Web\java\Python)工作,主要服务于生产制造 现拥有 Oracle 11g OCP/OCM、 Mysql、Oceanbase(OBCA)认证 分布式TBase\TDSQL数据库、国…

HMM

Author: 李文乐;Email: cocoleYYoutlook.comDatawhale 直观理解 马尔可夫链(英语:Markov chain),又称离散时间马尔可夫链(discrete-time Markov chain,缩写为DTMC),因俄国数学家安德…

hwui简介

简介: hwui主要是android用于2d硬件绘图而加入的一个模块,在hwui之前,android主要是用skia来进行软件绘制,后由于绘制性能等问题,现在android的绘图几乎都是使用了hwui硬件加速绘图。hwui主要则是使用opengles来进行g…