【JavaEE】Java设计模式-单例模式(饿汉式与懒汉式)
目录
1.设计模式是啥?
2.单例模式
2.1什么是单例模式
2.2饿汉模式
2.3懒汉模式
3.懒汉模式与饿汉模式的区别
3.1.线程安全方面
3.2.资源加载和性能
4.如何保证懒汉模式的线程安全
1.设计模式是啥?
设计模式是前人经过总结,通过对不同应用场景应该运用何种方法解决问题的模式。我们可以将它看成NBA中的战术(例如:电梯门战术),在应对不同的队伍时,需要运用不同的战术,针对不一样的队伍用不一样的战术才能更高效的得分,这就相当于对不同的问题有固定的模板免得去思考,可以直接去使用。故可认为:它是解决待定问题的一系列套路,是前辈们的代码设计经验的总结,具有一定的普遍性,可以重复使用。其目的是为了提高代码的可重用性、代码的可读性和代码的可靠性。
2.单例模式
2.1什么是单例模式
这个就看字面意思就很好理解,就是只能有一个例子,也就是该类只能new一个对象。
官方的说就是:这种模式涉及到一个单一的类,该类负责创建自己的对象,同时确保只有单个对象被创建。这个类提供了一种访问其唯一的对象的方式,可以直接访问,不需要实例化该类的对象。
目前单例模式有两种:1.饿汉式 2.懒汉式
如何实现单例模式呢?我们就从者两个模式的具体实现来说明吧!
2.2饿汉模式
饿汉式单例模式实现步骤:
1.将构造器私有化
解释:防止用户构造新对象
2.在类中创建好一个对象
解释:因为我们把构造器进行了私有化操作,但我们单例模式中需要有个对象,因此我们需要在类中实例化好一个对象。
3.创建一个方法,或者类中创建好的对象
解释:因为我们外部不能创建对象,但是我们类中有创建好的对象,因此我们需要一个方法来将对象给取出来。
代码实现:
class Singleton {private static Singleton instance=new Singleton();public static Singleton getS() {return instance;}private Singleton(){};
}
public class testDemo1 {public static void main(String[] args) {Singleton singleton=Singleton.getS();}
}
注意:
观察代码,有几个细节需要注意;因为用户不可以创建对象,因此我们需要在类中创建好对象,不能创建对象,就意味着我们不能通过对象引用类中的成员方法与成员变量,即在类中new对象时和获得new好的对象时需要用静态成员变量和静态成员方法,通过类名来访问。
2.3懒汉模式
懒汉式单例模式实现步骤:
1.将构造器私有化
解释:防止用户构造新对象
2.在类中创建好一个对象
解释:因为我们把构造器进行了私有化操作,但我们单例模式中需要有个对象,因此我们需要在类中实例化好一个对象。
3.创建一个方法,或者类中创建好的对象
解释:因为我们外部不能创建对象,但是我们类中有创建好的对象,因此我们需要一个方法来将对象给取出来。
class SingleLazy{private static SingleLazy instance=null;public static SingleLazy getInstance() {if(instance==null) {instance=new SingleLazy();}return instance;}private SingleLazy() {}
}
public class testDemo2 {SingleLazy singleLazy=SingleLazy.getInstance();
}
注意:
观察代码,有几个细节需要注意;因为用户不可以创建对象,因此我们需要在类中创建好对象,不能创建对象,就意味着我们不能通过对象引用类中的成员方法与成员变量,即在类中new对象时和获得new好的对象时需要用静态成员变量和静态成员方法,通过类名来访问。
与饿汉模式不同之处时,懒汉模式只有在调用到这个对象时,对象才得以创建,在没有调用之前,创建出来的对象时null,懒汉模式要比饿汉模式节省一些不必要的资源。
3.懒汉模式与饿汉模式的区别
3.1.线程安全方面
饿汉式天生就是线程安全的,因为饿汉模式当中仅仅只有读操作,可以直接用于多线程而不会出现问题,懒汉式本身是非线程安全的,懒汉模式线程不安全是因为他在创造对象时会产生指令重排序。
3.2.资源加载和性能
饿汉式在类创建的同时就实例化一个静态对象出来,不管之后会不会使用这个单例,都会占据一定的内存,但是相应的,在第一次调用时速度也会更快,因为其资源已经初始化完成。
懒汉式顾名思义,会延迟加载,在第一次使用该单例的时候才会实例化对象出来,第一次调用时要做初始化,如果要做的工作比较多,性能上会有些延迟。
4.如何保证懒汉模式的线程安全
首先我们要了解什么是线程不安全:
- 抢占式执行
修改操作,不是原子性的
内存可见性,引发的线程不安全
指令重排序引发的线程不安全
多线程修改同一个变量引发的线程不完全
具体的上方具体解读可以参考这篇文章理解:【JavaEE】 多线程的风险-线程安全
我们对标一下在懒汉模式中有几条是符合上方条件的

在懒汉模式getInstance()方法中,对instance对象即包括了读操作,也包括了写操作;在操作时,会发生指令重排序这对于多线程是不完全的。
这样说不是很只管,我们画图来说明(这里的例子仅代表一种情况):

这种情况我们如何避免呢?很好整,不同的问题,我们就不同的方案来解决,这时的解决方法就是给代码加锁。

这样我们就可以阻止指令重排序,让写操作在同一个线程内完成了!
真的就完成了吗?
并非如此,试想:在instance初始化之前,还是instance初始化之后,都会导致阻塞,存在大量的锁竞争,因此导致程序运行速度减慢(哪有一本万利的生意🐣)。
因此对于防止过多的锁竞争,我们需要再次改进代码:再加入一个判断(虽然有两个相同的if判断,但是两个判断的初心不同),判断instance是否初始化,如果已经初始化过了,就不需要再次加锁了。

还有一个问题没有解决就是内存可见性的问题。
如果有多个线程都调用getInstance()方法,就会有大量的读instance操作,我们知道对于访问内存与寄存器,访问寄存器的速度要比内存高几个数量级;因此,编译器就会自作主张优化掉访问内存的操作;即:将读内存的操作优化为读寄存器的操作。
为了保证内存可见性,我们需要将 在创建instance对象的语句上加上volatile关键字,来保证内存可见性。
完整代码如下:
class SingleLazy{private volatile static SingleLazy instance=null;//创建一个实例对象public static SingleLazy getInstance() {//判断是否需要加锁if(instance==null) {synchronized (SingleLazy.class) {//判断对象是否实例化if (instance == null) {instance = new SingleLazy();}}}return instance;}private SingleLazy() {}
}
写在最后:
以上就是本文全部内容,如果对你有所帮助,希望能留下你的点赞+关注,我会更加努力的更新内容!非常感谢🧡🧡🧡
若本篇文章有错误的地方,欢迎大佬们指正!

相关文章:
【JavaEE】Java设计模式-单例模式(饿汉式与懒汉式)
目录 1.设计模式是啥? 2.单例模式 2.1什么是单例模式 2.2饿汉模式 2.3懒汉模式 3.懒汉模式与饿汉模式的区别 3.1.线程安全方面 3.2.资源加载和性能 4.如何保证懒汉模式的线程安全 1.设计模式是啥? 设计模式是前人经过总结,通过…...
(算法基础)朴素版Prim算法
适用情景在最小生成树问题当中,涉及到权重和最小值。并且这个图是稠密图(n^2 ~ m)的情形下时间复杂度O(N^2)算法解释先得知道一下什么是无向图的生成树,树总该知道的吧,生成树就是包含这个无向图中的n个点,并且有n-1条边ÿ…...
第十四届蓝桥杯三月真题刷题训练——第 23 天
目录 第 1 题:长草 题目描述 输入描述 输出描述 输入输出样例 运行限制 代码: 思路: 第 2 题:蓝肽子序列_LCS_最长公共子序列dp问题 题目描述 输入描述 输出描述 输入输出样例 运行限制 代码: 思路&am…...
基于springboot实现医院信息管理系统【源码+论文】
基于springboot实现医院信管系统演示开发语言:Java 框架:springboot JDK版本:JDK1.8 服务器:tomcat7 数据库:mysql 5.7 数据库工具:Navicat11 开发软件:eclipse/myeclipse/idea Maven包…...
CODESYS增量式PID功能块(ST完整源代码)
增量式PID的详细算法公式和博途源代码,请参看下面的文章链接: 博途1200/1500PLC增量式PID算法(详细SCL代码)_博图scl语言pid增量编码器_RXXW_Dor的博客-CSDN博客SMART200PLC增量式PID可以参看下面这篇博文,文章里有完整的增量式PID算法公式,这里不在赘述西门子SMARTPLC增量…...
代码质量提升,代码扫描 review 之 Codacy 工具使用
目录一、什么是Codacy二、GitHub 上使用 Codacy三、Codacy上导入GitHub项目一、什么是Codacy Codacy 是用于代码 review 检测(即代码审查)的工具,目前支持对40多种编程语言检测,如 c、c、c#、java 、python、javascript 等。 Codacy 可用于 GitHub 和 …...
Centos Linux 正确安装 Redis 的方式
官方文档 Getting started with Redis | Redis 第一步 、下载源代码 源代码的下载方式有很多种,可以去源代码仓库下载,或者使用下面的命令下载 wget https://download.redis.io/redis-stable.tar.gz 第二步 、编译代码 tar -xzvf redis-stable.tar.…...
C++Primer第五版【阅读笔记】
CPrimer第五版 阅读笔记 第1章开始1.1 编写一个简单的C程序1.1.1 编译、运行程序1.2 初识输入输出第1章开始 学习一门新的程序设计语言的最好方法就是练习编写程序。 1.1 编写一个简单的C程序 每个C程序都包含一个或多个函数,其中一个必须命名为 main,…...
ERD Online 4.0.11 在线数据库建模、元数据协作平台(免费、私有部署)
ERD Online 是全球第一个开源、免费在线数据建模、元数据管理平台。提供简单易用的元数据设计、关系图设计、SQL查询等功能,辅以版本、导入、导出、数据源、SQL解析、审计、团队协作等功能、方便我们快速、安全的管理数据库中的元数据。 4.0.11 ❝ :memo: fix(erd):…...
3.数组算法、动态规划
文章目录数组算法1.数组表示2.基本操作3.插入操作算法实例1实例2输出3.删除操作算法实例1输出4.搜索操作算法实例2输出5.更新操作算法实3例输出2.动态规划对照实例1数组算法 Array是一个容器,可以容纳固定数量的项目,这些项目应该是相同的类型。大多数数…...
项目管理工具哪个好?最新排名
项目管理工具当下已经成为项目团队的重要榜首,一款合适好用的项目管理工具可以帮助处理很多机械化工作,将管理者更多精力投入到更有价值的工作中,还可以帮助团队组织和计划项目,跟踪进度,处理预算和协作。该如何挑选帮…...
650. 只有两个键的键盘——【Leetcode每日一题】
650. 只有两个键的键盘 最初记事本上只有一个字符 A 。你每次可以对这个记事本进行两种操作: Copy All(复制全部):复制这个记事本中的所有字符(不允许仅复制部分字符)。Paste(粘贴)…...
【平常心无焦虑探讨】未来谁将被淘汰—在日常网络安全工作中使用GPT的感受
作者:Eason_LYC 悲观者预言失败,十言九中。 乐观者创造奇迹,一次即可。 一个人的价值,在于他所拥有的。所以可以不学无术,但不能一无所有! 技术领域:WEB安全、网络攻防 关注WEB安全、网络攻防。…...
【C语言】深度理解指针(下)
一. 前言💎昨晚整理博客时突然发现指针还少了一篇没写,今天就顺便来补一补。上回书说到,emmm忘记了,没事,我们直接进入本期的内容:本期我们带来了几道指针相关笔试题的解析,还算是相对比较轻松的。话不多说…...
【树与二叉树】树与二叉树的概念及结构--详解介绍
📝个人主页:Sherry的成长之路 🏠学习社区:Sherry的成长之路(个人社区) 📖专栏链接:数据结构 🎯长路漫漫浩浩,万事皆有期待 文章目录1.树概念及结构1.1 树…...
Spring Boot集成RocketMQ实现普通、延时、事务消息发送接收、PULL消费模式及开启ACL | Spring Cloud 30
一、前言 在前面我们通过以下章节对RocketMQ有了基础的了解: docker-compose 搭建RocketMQ 5.1.0 集群(双主双从模式) | Spring Cloud 28 docker-compose 搭建RocketMQ 5.1.0 集群开启ACL权限控制 | Spring Cloud 29 现在开始我们正式学习…...
人人都能看懂的Spring源码解析,Spring如何解决循环依赖
人人都能看懂的Spring源码解析,Spring如何解决循环依赖原理解析什么是循环依赖循环依赖会有什么问题?如何解决循环依赖问题的根本原因如何解决为什么需要三级缓存?Spring的三级缓存源码走读Spring的三级缓存提前暴露getSingleton方法总结往期…...
Linux上搭建Discuz论坛
一.准备工作 1.下载php*,mariadb-server 2.上传Discuz3.5压缩包并解压 二.搭建过程 基于redhat 9 版本和Discuz3.5,php8.0,mariadb10.5演示 一.准备工作 1.下载php*,mariadb-server [rootredhat9 aaa]# yum install -y php*…...
【蓝桥杯专题】 树状数组(C++ | 洛谷 | acwing | 蓝桥)
菜狗现在才开始备战蓝桥杯QAQ 文章目录【蓝桥杯专题】 (C | 洛谷 | acwing | 蓝桥)什么是线段数组??1264. 动态求连续区间和数星星线段树AcWing 1270. 数列区间最大值PPPPPPP【蓝桥杯专题】 (C | 洛谷 | acwing | 蓝桥) 什么是…...
QCefView编译配置(Windows-MSVC)(11)
QCefView编译配置(Windows-MSVC) 文章目录QCefView编译配置(Windows-MSVC)1、概述2、准备工作3、添加环境变量4、更换cef源码版本5、CMake构建6、Visual Studio编译7、安装编译后的文件8、验证编译结果更多精彩内容👉个…...
3.3.1_1 检错编码(奇偶校验码)
从这节课开始,我们会探讨数据链路层的差错控制功能,差错控制功能的主要目标是要发现并且解决一个帧内部的位错误,我们需要使用特殊的编码技术去发现帧内部的位错误,当我们发现位错误之后,通常来说有两种解决方案。第一…...
Day131 | 灵神 | 回溯算法 | 子集型 子集
Day131 | 灵神 | 回溯算法 | 子集型 子集 78.子集 78. 子集 - 力扣(LeetCode) 思路: 笔者写过很多次这道题了,不想写题解了,大家看灵神讲解吧 回溯算法套路①子集型回溯【基础算法精讲 14】_哔哩哔哩_bilibili 完…...
ElasticSearch搜索引擎之倒排索引及其底层算法
文章目录 一、搜索引擎1、什么是搜索引擎?2、搜索引擎的分类3、常用的搜索引擎4、搜索引擎的特点二、倒排索引1、简介2、为什么倒排索引不用B+树1.创建时间长,文件大。2.其次,树深,IO次数可怕。3.索引可能会失效。4.精准度差。三. 倒排索引四、算法1、Term Index的算法2、 …...
华硕a豆14 Air香氛版,美学与科技的馨香融合
在快节奏的现代生活中,我们渴望一个能激发创想、愉悦感官的工作与生活伙伴,它不仅是冰冷的科技工具,更能触动我们内心深处的细腻情感。正是在这样的期许下,华硕a豆14 Air香氛版翩然而至,它以一种前所未有的方式&#x…...
基于Springboot+Vue的办公管理系统
角色: 管理员、员工 技术: 后端: SpringBoot, Vue2, MySQL, Mybatis-Plus 前端: Vue2, Element-UI, Axios, Echarts, Vue-Router 核心功能: 该办公管理系统是一个综合性的企业内部管理平台,旨在提升企业运营效率和员工管理水…...
关于easyexcel动态下拉选问题处理
前些日子突然碰到一个问题,说是客户的导入文件模版想支持部分导入内容的下拉选,于是我就找了easyexcel官网寻找解决方案,并没有找到合适的方案,没办法只能自己动手并分享出来,针对Java生成Excel下拉菜单时因选项过多导…...
LangFlow技术架构分析
🔧 LangFlow 的可视化技术栈 前端节点编辑器 底层框架:基于 (一个现代化的 React 节点绘图库) 功能: 拖拽式构建 LangGraph 状态机 实时连线定义节点依赖关系 可视化调试循环和分支逻辑 与 LangGraph 的深…...
学习一下用鸿蒙DevEco Studio HarmonyOS5实现百度地图
在鸿蒙(HarmonyOS5)中集成百度地图,可以通过以下步骤和技术方案实现。结合鸿蒙的分布式能力和百度地图的API,可以构建跨设备的定位、导航和地图展示功能。 1. 鸿蒙环境准备 开发工具:下载安装 De…...
rknn toolkit2搭建和推理
安装Miniconda Miniconda - Anaconda Miniconda 选择一个 新的 版本 ,不用和RKNN的python版本保持一致 使用 ./xxx.sh进行安装 下面配置一下载源 # 清华大学源(最常用) conda config --add channels https://mirrors.tuna.tsinghua.edu.cn…...
【51单片机】4. 模块化编程与LCD1602Debug
1. 什么是模块化编程 传统编程会将所有函数放在main.c中,如果使用的模块多,一个文件内会有很多代码,不利于组织和管理 模块化编程则是将各个模块的代码放在不同的.c文件里,在.h文件里提供外部可调用函数声明,其他.c文…...
