JavaEE 第8节 单例模式详解
目录
概念
饿汉模式
懒汉模式
懒汉模式在多线程环境下的优化
1.线程安全问题
2.效率问题
3.指令重排序导致的问题
1)为什么要进行指令重排序?
2)指令重排序在上述代码为什么会构成问题?
导读:
单例模式是一种设计模式。
简单来讲设计模式就类似于下棋的棋谱,在特定的场景下使用这种模式(固定套路),可以让程序达到一个不错的效果。设计模式也是和编程语言相关的,有些设计模式是在给一些语言的语法填坑,而有些语言又不太依赖设计模式。
设计模式适合具有一定编程经验之后再去主要学习,如果缺乏变成经验,难以理解,别人这么设计的好处。
概念
单例模式的概念很简单,顾名思义,既在一个线程中一个类只包含一个对应的实例化对象。
在多线程程序中,有些场景就是要求只能创建一个实例化对象。
比如JDBC的设置数据源:
一个数据库,对应的MySQL服务器只有一份,DataSoruce这个类就没有必要new多份。
当然JDBC这块知识不了太解没关系,主要是告诉你,单例模式在多线程程序中其实是非常重要的。
单例模式的写法有很多,这里介绍两个最常用、最主流的写法:饿汉模式与懒汉模式。
饿汉模式
饿汉的饿,其实突出的是实例的创建时间比较早,是在类被加载的时候就创建了(可以近似的理解为在程序启动时创建)
为SingleL类写一个单例模式,用饿汉模式:
class SingleL{private static SingleL singleL=new SingleL();//直接new一个public static SingleL getSingleL(){return singleL;}
}
懒汉模式
懒汉的懒,其实突出的是实例的创建时间比较晚。
这里的晚,指的是,程序在需要这个类的时候才去实例化它:
class SingleL{private static SingleL instance=null;//先置为空,要的时候才实例化public static SingleL getInstance(){if(instance==null){//没有创建,先创建,有就直接返回instance=new SingleL();}return instance;}}
懒汉模式有一个优点,就是效率高,在计算机中懒其实是一个褒义词,勤快反而是一个贬义词。
为什么这么说呢?
最典型的场景就是打开一个内存比较大的文档,为了有一个更好的用户体验,响应速度因该是越快越好的,如果程序加载很“勤快”(提前加载完所有文档内容),打开文档程序所需的时间势必会变长,用户体验感就会变差。
但是如果程序加载比较的“懒”(先只加载几页,之用户想要看那一页,在加载那一页),响应速度就变得快了,用户体验感也会不错。
懒汉模式在多线程环境下的优化
1.线程安全问题
刚才的懒汉模式的代码在多线程环境下,肯定会造成线程安全问题,因为程序中不仅对变量进行了修改,而且读取和修改操作不是原子性的。
class SingleL{private static Object lock=new Object();private static SingleL instance=null;//先置为空,要的时候才实例化public static SingleL getInstance(){synchronized(lock){/*注意读写操作都要放到同步块中*/if(instance==null){instance=new SingleL();}}return instance;//返回之加不加到同步块中都无所谓,因为线程安全问题已经解决}
}
2.效率问题
这个问题是由上面解决了线程安全问题诱发的新的问题。
public static SingleL getInstance(){synchronized(lock){/*注意读写操作都要放到同步块中*/if(instance==null){instance=new SingleL();}}return instance;//返回之加不加到同步块中都无所谓,因为线程安全问题已经解决}
假如说由多个线程都要调用getInstance()那么就很可能导致多次的上锁和解锁,因为每次都要去判断有没有创建这个单例对象,这是非常消耗时间的。
解决办法也很简单,就是在线程安全的情况下,再次判断instance是否为null:
class SingleL{private static Object lock=new Object();private static SingleL instance=null;//先置为空,要的时候才实例化public static SingleL getInstance(){if(instance==null){synchronized(lock){/*注意读写操作都要放到同步块中*/if(instance==null){instance=new SingleL();}}}return instance;//返回之加不加到同步块中都无所谓,因为线程安全问题已经解决}
}
这就极大避免了多次上锁的情况了,你细品,两个if(instance==null)都不是多余的!
3.指令重排序导致的问题
1)为什么要进行指令重排序?
指令重排序和内存可见性一样都是编译器为了优化程序而引入的。
假如说有1、2、3条指令。这三条指令如果顺序执行可能是不经济的。例如执行1指令的时候需要和某个其他的指令同时争抢某一个资源导致冲突,但是如果先执行2,然后执行1就可以避免这种情况发生。
再比如这个形象的例子,老妈让你出去菜市场买三样东西:葱、姜、蒜:

为了节省时间继续打游戏,当然先去姜蒜两个摊位把东西买了,然后最后去葱这个摊位买啊。
2)指令重排序在上述代码为什么会构成问题?
在优化后的代码中new SingleL在编译时,可以大致分解成三个指令:
1、给对象分配内存空间。
2、调用构造函数初始化对象
3、讲instance引用指向分配内存的空间
通过指令重排序后,可能先执行1,然后直接执行3,最后执行2。
这样就会出现一个不安全的时机,就是1、3都执行完了,但是2还没有执行,此时instance引用指向的是一个无效的内存,因为还没有初始化好对象。
然后我们回到代码中来,假如说有两个线程,他们都刚开始执行,单例对象还没有创建:



3)问题的解决办法
指令重排序和内存可见性问题解决方式是一样的,用volatile关键字修饰变量。
volatile的作用:
1、保证变量可见性:一个线程对volatile变量修改,另一个线程可以立马看到。
2、禁止指令重排序:防止编译器对volatile变量的读/写操作进行指令重排序。
优化后的代码:
class SingleL{private static Object lock=new Object();private static volatile SingleL instance=null;//先置为空,要的时候才实例化,最后volatile禁止指令重排序public static SingleL getInstance(){if(instance==null){/*在同步块中执行*/synchronized(lock){if(instance==null){instance=new SingleL();}}}return instance;}
}
相关文章:
JavaEE 第8节 单例模式详解
目录 概念 饿汉模式 懒汉模式 懒汉模式在多线程环境下的优化 1.线程安全问题 2.效率问题 3.指令重排序导致的问题 1)为什么要进行指令重排序? 2)指令重排序在上述代码为什么会构成问题? 导读: 单例模式是一种…...
OpenAI 发布 GPT-4o 模型安全评估报告:风险等级为“中等”|TodayAI
OpenAI 近日发布了最新的 GPT-4o 系统卡,这是一份研究文件,详细介绍了公司在推出其最新 AI 模型之前所进行的安全措施和风险评估。根据该评估报告,GPT-4o 的总体风险等级被评定为 “中等” 。 GPT-4o 于今年 5 月首次公开发布。在其发布之前…...
学习前端面试知识
2024-8-9 打卡第十天 学习视频链接 js延迟加载 延迟加载:等页面加载完成后再进行加载提高页面加载速度defer属性,同步加载,让脚本与文档同步解析,顺序执行,当文档解析完成再执行defer,执行完再执行脚本&…...
Leetcode JAVA刷刷站(9)回文数
一、题目概述 二、思路方向 在Java中,判断一个整数是否为回文数,可以通过将该整数转换为字符串,然后比较字符串与其反转后的字符串是否相同来实现。但这种方法在整数非常大时可能不太高效,因为它依赖于字符串操作。一个更高效的方…...
数据结构算法
⩕ 单调栈 1、概念 对于一个栈,维持其单调性,有两种情况,单调递增栈:由栈底到栈顶单调递增 单调递减栈:由栈底到栈顶单调递减 2、核心模板( 单调递增栈 ) stack<int> stk; void …...
WordPress个性化站点
这个信息爆炸的时代,拥有一个能够迅速传达信息、展示个性、并能够与世界互动的在线平台,已成为企业和个人的基本需求。WordPress以其无与伦比的易用性和强大的扩展性,成为了构建此类平台的首选工具。而LNMP是由Linux、Nginx、MySQL和PHP组成的…...
GESP C++ 2024年03月一级真题卷
一、单选题(每题 2 分,共 30 分) 第 1 题 C表达式 (3 - 2) * 3 5 的值是( )。 A. -13 B. 8 C. 2 D. 0 答案:B 解析:略 第 2 题 C 语句 cout << "5%2" << 5 % 2 执行后的输出是…...
Linux驱动开发基础(Hello驱动)
所学内容来自百问网 目录 1. 文件在内核中的表示 2. 打开字符设备节点时,内核中也有对应的struct file 3. 编写驱动程序步骤 4. 相关知识点 4.1 涉及函数解析 4.2 module_init/module_exit的实现 4.3 register_chrdev的内部实现 4.4 class_destroy/device_…...
centos7安装 ES集群 elasticsearch
这里写自定义目录标题 编写启动脚本 elasticsearch.sh启动可能报错:elasticsearch 7.10启动报错 bootstrap checks failed解决方法问题原因:注意 退出xshell,重新登录: 上面两个配置项改完后,ES启动用户(es 或root) **…...
互联网应用主流框架整合【Redis数据结构及常用命令】
在大部分情况下我们使用Redis只是执行一些简单的命令操作,通常无需区分是否是在一个连接池里的同一个链接去执行,如果需要执行多条命令,需要保证命令在同一个链接里完成,则采用SessionCallback接口操作即可 Redis数据结构-字符串…...
GORM 自动迁移与命名策略
在现代软件开发中,数据库结构的维护和迁移是常见的挑战之一。GORM,作为 Go 语言中强大的 ORM 库,提供了自动迁移功能,帮助开发者轻松地管理数据库表结构的变更。此外,GORM 还允许开发者通过命名策略(Naming…...
python社会科学问题研究的计算实验
实验十五:社会科学问题研究的计算实践 1.实验目标及要求 (1)掌握网络视角 (2)掌握社会网络基础内容 (3)掌握友谊悖论 2.实验主要内容 随机生成一次符合社会网络特征的网络,通过计…...
Element Plus 发布 2.8.0
功能特性 组件更新 [color-picker] alpha-slider a11y (#14245 by tolking)添加 mention 组件 (#17586 by Fuphoenixes)[tree-v2] 添加 scrollTo 方法 (#14050 by kaine0923)[drawer] 添加 append-to 属性 (#17761 by tolking)[table] tree children 添加严格检查 (#13519 by t…...
解释区块链技术的应用场景和优势-水文
区块链技术是一种去中心化的分布式账本技术,其应用场景和优势如下: 金融领域:区块链可以用于加密货币交易,提供安全的、去中心化的支付系统。它也可以用于股票、债券和其他金融交易的记录和结算,提高交易的透明度和效率…...
等保测评基础知识(一)
1、时间类: 网络安全法: 2017年6月1日等保2.0实施时间: 2019年12月1日密码法: 2020年1月1日个人信息保护法: 2021年11月1日,数据安全法实施时间: 2021年9月1日关键信息基础…...
股指期货套期保值中的展期管理有哪些?
在复杂的金融市场环境中,展期作为一种重要的风险管理工具,被广泛应用于期货交易中,特别是当投资者需要对长期资产进行套期保值时。展期的核心思想在于,通过连续替换高流动性的近月期货合约来替代流动性较差的远月合约,…...
如何通过参考文献找到原文
当只有参考文献想要获取原文时,通常会用到以下方法: 举例参考文献1. 杨忠华,周勃,宁宝宽,等.面向新能源产业的专业研究生研创能力培养实践探索——基于“政产学研用”融合驱动[J].高教学刊,2024,10(23):19-22.DOI:10.19980/j.CN23-1593/G4.2024.23.004…...
春秋云境 | SQL | CVE-2022-4230
目录 靶标介绍 开启靶场 wpscan漏洞介绍 查询数据库表名 查询表中字段名 查询字段下数据 靶标介绍 WP Statistics WordPress 插件13.2.9之前的版本不会转义参数,这可能允许经过身份验证的用户执行 SQL 注入攻击。默认情况下,具有管理选项功能 (ad…...
3.串口(UART)
串口理论部分可看51部分:链接 数据帧 帧头(2字节,例如AA、BB) 数据长度(2字节) 数据 CRC16校验(2字节) 帧尾(2字节) 代码编写 串口一发送命令控制LED灯(PB5、PE5) LED灯、串口、…...
macOS Sonoma 14.6.1 (23G93) Boot ISO 原版可引导镜像下载
macOS Sonoma 14.6.1 (23G93) Boot ISO 原版可引导镜像下载 2024 年 8 月 8 日凌晨,macOS Sonoma 14.6.1 发布,本更新包含了重要的错误修复,并解决了导致高级数据保护无法启用或停用的问题。同时带来了 macOS Ventura 13.6.9 安全更新。 本…...
java_网络服务相关_gateway_nacos_feign区别联系
1. spring-cloud-starter-gateway 作用:作为微服务架构的网关,统一入口,处理所有外部请求。 核心能力: 路由转发(基于路径、服务名等)过滤器(鉴权、限流、日志、Header 处理)支持负…...
STM32+rt-thread判断是否联网
一、根据NETDEV_FLAG_INTERNET_UP位判断 static bool is_conncected(void) {struct netdev *dev RT_NULL;dev netdev_get_first_by_flags(NETDEV_FLAG_INTERNET_UP);if (dev RT_NULL){printf("wait netdev internet up...");return false;}else{printf("loc…...
可靠性+灵活性:电力载波技术在楼宇自控中的核心价值
可靠性灵活性:电力载波技术在楼宇自控中的核心价值 在智能楼宇的自动化控制中,电力载波技术(PLC)凭借其独特的优势,正成为构建高效、稳定、灵活系统的核心解决方案。它利用现有电力线路传输数据,无需额外布…...
抖音增长新引擎:品融电商,一站式全案代运营领跑者
抖音增长新引擎:品融电商,一站式全案代运营领跑者 在抖音这个日活超7亿的流量汪洋中,品牌如何破浪前行?自建团队成本高、效果难控;碎片化运营又难成合力——这正是许多企业面临的增长困局。品融电商以「抖音全案代运营…...
srs linux
下载编译运行 git clone https:///ossrs/srs.git ./configure --h265on make 编译完成后即可启动SRS # 启动 ./objs/srs -c conf/srs.conf # 查看日志 tail -n 30 -f ./objs/srs.log 开放端口 默认RTMP接收推流端口是1935,SRS管理页面端口是8080,可…...
MySQL 8.0 OCP 英文题库解析(十三)
Oracle 为庆祝 MySQL 30 周年,截止到 2025.07.31 之前。所有人均可以免费考取原价245美元的MySQL OCP 认证。 从今天开始,将英文题库免费公布出来,并进行解析,帮助大家在一个月之内轻松通过OCP认证。 本期公布试题111~120 试题1…...
Unit 1 深度强化学习简介
Deep RL Course ——Unit 1 Introduction 从理论和实践层面深入学习深度强化学习。学会使用知名的深度强化学习库,例如 Stable Baselines3、RL Baselines3 Zoo、Sample Factory 和 CleanRL。在独特的环境中训练智能体,比如 SnowballFight、Huggy the Do…...
聊一聊接口测试的意义有哪些?
目录 一、隔离性 & 早期测试 二、保障系统集成质量 三、验证业务逻辑的核心层 四、提升测试效率与覆盖度 五、系统稳定性的守护者 六、驱动团队协作与契约管理 七、性能与扩展性的前置评估 八、持续交付的核心支撑 接口测试的意义可以从四个维度展开,首…...
Element Plus 表单(el-form)中关于正整数输入的校验规则
目录 1 单个正整数输入1.1 模板1.2 校验规则 2 两个正整数输入(联动)2.1 模板2.2 校验规则2.3 CSS 1 单个正整数输入 1.1 模板 <el-formref"formRef":model"formData":rules"formRules"label-width"150px"…...
在Mathematica中实现Newton-Raphson迭代的收敛时间算法(一般三次多项式)
考察一般的三次多项式,以r为参数: p[z_, r_] : z^3 (r - 1) z - r; roots[r_] : z /. Solve[p[z, r] 0, z]; 此多项式的根为: 尽管看起来这个多项式是特殊的,其实一般的三次多项式都是可以通过线性变换化为这个形式…...
