【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、验证编译结果更多精彩内容👉个…...
【Python】 -- 趣味代码 - 小恐龙游戏
文章目录 文章目录 00 小恐龙游戏程序设计框架代码结构和功能游戏流程总结01 小恐龙游戏程序设计02 百度网盘地址00 小恐龙游戏程序设计框架 这段代码是一个基于 Pygame 的简易跑酷游戏的完整实现,玩家控制一个角色(龙)躲避障碍物(仙人掌和乌鸦)。以下是代码的详细介绍:…...
Prompt Tuning、P-Tuning、Prefix Tuning的区别
一、Prompt Tuning、P-Tuning、Prefix Tuning的区别 1. Prompt Tuning(提示调优) 核心思想:固定预训练模型参数,仅学习额外的连续提示向量(通常是嵌入层的一部分)。实现方式:在输入文本前添加可训练的连续向量(软提示),模型只更新这些提示参数。优势:参数量少(仅提…...
盘古信息PCB行业解决方案:以全域场景重构,激活智造新未来
一、破局:PCB行业的时代之问 在数字经济蓬勃发展的浪潮中,PCB(印制电路板)作为 “电子产品之母”,其重要性愈发凸显。随着 5G、人工智能等新兴技术的加速渗透,PCB行业面临着前所未有的挑战与机遇。产品迭代…...
基于uniapp+WebSocket实现聊天对话、消息监听、消息推送、聊天室等功能,多端兼容
基于 UniApp + WebSocket实现多端兼容的实时通讯系统,涵盖WebSocket连接建立、消息收发机制、多端兼容性配置、消息实时监听等功能,适配微信小程序、H5、Android、iOS等终端 目录 技术选型分析WebSocket协议优势UniApp跨平台特性WebSocket 基础实现连接管理消息收发连接…...
Python如何给视频添加音频和字幕
在Python中,给视频添加音频和字幕可以使用电影文件处理库MoviePy和字幕处理库Subtitles。下面将详细介绍如何使用这些库来实现视频的音频和字幕添加,包括必要的代码示例和详细解释。 环境准备 在开始之前,需要安装以下Python库:…...
C# SqlSugar:依赖注入与仓储模式实践
C# SqlSugar:依赖注入与仓储模式实践 在 C# 的应用开发中,数据库操作是必不可少的环节。为了让数据访问层更加简洁、高效且易于维护,许多开发者会选择成熟的 ORM(对象关系映射)框架,SqlSugar 就是其中备受…...
c#开发AI模型对话
AI模型 前面已经介绍了一般AI模型本地部署,直接调用现成的模型数据。这里主要讲述讲接口集成到我们自己的程序中使用方式。 微软提供了ML.NET来开发和使用AI模型,但是目前国内可能使用不多,至少实践例子很少看见。开发训练模型就不介绍了&am…...
06 Deep learning神经网络编程基础 激活函数 --吴恩达
深度学习激活函数详解 一、核心作用 引入非线性:使神经网络可学习复杂模式控制输出范围:如Sigmoid将输出限制在(0,1)梯度传递:影响反向传播的稳定性二、常见类型及数学表达 Sigmoid σ ( x ) = 1 1 +...
SiFli 52把Imagie图片,Font字体资源放在指定位置,编译成指定img.bin和font.bin的问题
分区配置 (ptab.json) img 属性介绍: img 属性指定分区存放的 image 名称,指定的 image 名称必须是当前工程生成的 binary 。 如果 binary 有多个文件,则以 proj_name:binary_name 格式指定文件名, proj_name 为工程 名&…...
springboot整合VUE之在线教育管理系统简介
可以学习到的技能 学会常用技术栈的使用 独立开发项目 学会前端的开发流程 学会后端的开发流程 学会数据库的设计 学会前后端接口调用方式 学会多模块之间的关联 学会数据的处理 适用人群 在校学生,小白用户,想学习知识的 有点基础,想要通过项…...
