当前位置: 首页 > news >正文

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、概念 对于一个栈&#xff0c;维持其单调性&#xff0c;有两种情况&#xff0c;单调递增栈&#xff1a;由栈底到栈顶单调递增 单调递减栈&#xff1a;由栈底到栈顶单调递减 2、核心模板&#xff08; 单调递增栈 &#xff09; stack<int> stk; void …...

WordPress个性化站点

这个信息爆炸的时代&#xff0c;拥有一个能够迅速传达信息、展示个性、并能够与世界互动的在线平台&#xff0c;已成为企业和个人的基本需求。WordPress以其无与伦比的易用性和强大的扩展性&#xff0c;成为了构建此类平台的首选工具。而LNMP是由Linux、Nginx、MySQL和PHP组成的…...

GESP C++ 2024年03月一级真题卷

一、单选题&#xff08;每题 2 分&#xff0c;共 30 分&#xff09; 第 1 题 C表达式 (3 - 2) * 3 5 的值是( )。 A. -13 B. 8 C. 2 D. 0 答案&#xff1a;B 解析&#xff1a;略 第 2 题 C 语句 cout << "5%2" << 5 % 2 执行后的输出是…...

Linux驱动开发基础(Hello驱动)

所学内容来自百问网 目录 1. 文件在内核中的表示 2. 打开字符设备节点时&#xff0c;内核中也有对应的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启动可能报错&#xff1a;elasticsearch 7.10启动报错 bootstrap checks failed解决方法问题原因&#xff1a;注意 退出xshell&#xff0c;重新登录&#xff1a; 上面两个配置项改完后&#xff0c;ES启动用户(es 或root) **…...

互联网应用主流框架整合【Redis数据结构及常用命令】

在大部分情况下我们使用Redis只是执行一些简单的命令操作&#xff0c;通常无需区分是否是在一个连接池里的同一个链接去执行&#xff0c;如果需要执行多条命令&#xff0c;需要保证命令在同一个链接里完成&#xff0c;则采用SessionCallback接口操作即可 Redis数据结构-字符串…...

GORM 自动迁移与命名策略

在现代软件开发中&#xff0c;数据库结构的维护和迁移是常见的挑战之一。GORM&#xff0c;作为 Go 语言中强大的 ORM 库&#xff0c;提供了自动迁移功能&#xff0c;帮助开发者轻松地管理数据库表结构的变更。此外&#xff0c;GORM 还允许开发者通过命名策略&#xff08;Naming…...

python社会科学问题研究的计算实验

实验十五&#xff1a;社会科学问题研究的计算实践 1.实验目标及要求 &#xff08;1&#xff09;掌握网络视角 &#xff08;2&#xff09;掌握社会网络基础内容 &#xff08;3&#xff09;掌握友谊悖论 2.实验主要内容 随机生成一次符合社会网络特征的网络&#xff0c;通过计…...

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…...

解释区块链技术的应用场景和优势-水文

区块链技术是一种去中心化的分布式账本技术&#xff0c;其应用场景和优势如下&#xff1a; 金融领域&#xff1a;区块链可以用于加密货币交易&#xff0c;提供安全的、去中心化的支付系统。它也可以用于股票、债券和其他金融交易的记录和结算&#xff0c;提高交易的透明度和效率…...

等保测评基础知识(一)

1、时间类&#xff1a; 网络安全法&#xff1a; 2017年6月1日等保2.0实施时间&#xff1a; 2019年12月1日密码法&#xff1a; 2020年1月1日个人信息保护法&#xff1a; 2021年11月1日&#xff0c;数据安全法实施时间&#xff1a; 2021年9月1日关键信息基础…...

股指期货套期保值中的展期管理有哪些?

在复杂的金融市场环境中&#xff0c;展期作为一种重要的风险管理工具&#xff0c;被广泛应用于期货交易中&#xff0c;特别是当投资者需要对长期资产进行套期保值时。展期的核心思想在于&#xff0c;通过连续替换高流动性的近月期货合约来替代流动性较差的远月合约&#xff0c;…...

如何通过参考文献找到原文

当只有参考文献想要获取原文时&#xff0c;通常会用到以下方法&#xff1a; 举例参考文献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之前的版本不会转义参数&#xff0c;这可能允许经过身份验证的用户执行 SQL 注入攻击。默认情况下&#xff0c;具有管理选项功能 (ad…...

3.串口(UART)

串口理论部分可看51部分&#xff1a;链接 数据帧 帧头(2字节&#xff0c;例如AA、BB) 数据长度&#xff08;2字节&#xff09; 数据 CRC16校验&#xff08;2字节&#xff09; 帧尾&#xff08;2字节&#xff09; 代码编写 串口一发送命令控制LED灯(PB5、PE5) LED灯、串口、…...

macOS Sonoma 14.6.1 (23G93) Boot ISO 原版可引导镜像下载

macOS Sonoma 14.6.1 (23G93) Boot ISO 原版可引导镜像下载 2024 年 8 月 8 日凌晨&#xff0c;macOS Sonoma 14.6.1 发布&#xff0c;本更新包含了重要的错误修复&#xff0c;并解决了导致高级数据保护无法启用或停用的问题。同时带来了 macOS Ventura 13.6.9 安全更新。 本…...

OpenLayers 可视化之热力图

注&#xff1a;当前使用的是 ol 5.3.0 版本&#xff0c;天地图使用的key请到天地图官网申请&#xff0c;并替换为自己的key 热力图&#xff08;Heatmap&#xff09;又叫热点图&#xff0c;是一种通过特殊高亮显示事物密度分布、变化趋势的数据可视化技术。采用颜色的深浅来显示…...

MFC内存泄露

1、泄露代码示例 void X::SetApplicationBtn() {CMFCRibbonApplicationButton* pBtn GetApplicationButton();// 获取 Ribbon Bar 指针// 创建自定义按钮CCustomRibbonAppButton* pCustomButton new CCustomRibbonAppButton();pCustomButton->SetImage(IDB_BITMAP_Jdp26)…...

linux arm系统烧录

1、打开瑞芯微程序 2、按住linux arm 的 recover按键 插入电源 3、当瑞芯微检测到有设备 4、松开recover按键 5、选择升级固件 6、点击固件选择本地刷机的linux arm 镜像 7、点击升级 &#xff08;忘了有没有这步了 估计有&#xff09; 刷机程序 和 镜像 就不提供了。要刷的时…...

涂鸦T5AI手搓语音、emoji、otto机器人从入门到实战

“&#x1f916;手搓TuyaAI语音指令 &#x1f60d;秒变表情包大师&#xff0c;让萌系Otto机器人&#x1f525;玩出智能新花样&#xff01;开整&#xff01;” &#x1f916; Otto机器人 → 直接点明主体 手搓TuyaAI语音 → 强调 自主编程/自定义 语音控制&#xff08;TuyaAI…...

Fabric V2.5 通用溯源系统——增加图片上传与下载功能

fabric-trace项目在发布一年后,部署量已突破1000次,为支持更多场景,现新增支持图片信息上链,本文对图片上传、下载功能代码进行梳理,包含智能合约、后端、前端部分。 一、智能合约修改 为了增加图片信息上链溯源,需要对底层数据结构进行修改,在此对智能合约中的农产品数…...

JVM虚拟机:内存结构、垃圾回收、性能优化

1、JVM虚拟机的简介 Java 虚拟机(Java Virtual Machine 简称:JVM)是运行所有 Java 程序的抽象计算机,是 Java 语言的运行环境,实现了 Java 程序的跨平台特性。JVM 屏蔽了与具体操作系统平台相关的信息,使得 Java 程序只需生成在 JVM 上运行的目标代码(字节码),就可以…...

如何更改默认 Crontab 编辑器 ?

在 Linux 领域中&#xff0c;crontab 是您可能经常遇到的一个术语。这个实用程序在类 unix 操作系统上可用&#xff0c;用于调度在预定义时间和间隔自动执行的任务。这对管理员和高级用户非常有益&#xff0c;允许他们自动执行各种系统任务。 编辑 Crontab 文件通常使用文本编…...

Caliper 配置文件解析:fisco-bcos.json

config.yaml 文件 config.yaml 是 Caliper 的主配置文件,通常包含以下内容: test:name: fisco-bcos-test # 测试名称description: Performance test of FISCO-BCOS # 测试描述workers:type: local # 工作进程类型number: 5 # 工作进程数量monitor:type: - docker- pro…...

【Kafka】Kafka从入门到实战:构建高吞吐量分布式消息系统

Kafka从入门到实战:构建高吞吐量分布式消息系统 一、Kafka概述 Apache Kafka是一个分布式流处理平台,最初由LinkedIn开发,后成为Apache顶级项目。它被设计用于高吞吐量、低延迟的消息处理,能够处理来自多个生产者的海量数据,并将这些数据实时传递给消费者。 Kafka核心特…...

【免费数据】2005-2019年我国272个地级市的旅游竞争力多指标数据(33个指标)

旅游业是一个城市的重要产业构成。旅游竞争力是一个城市竞争力的重要构成部分。一个城市的旅游竞争力反映了其在旅游市场竞争中的比较优势。 今日我们分享的是2005-2019年我国272个地级市的旅游竞争力多指标数据&#xff01;该数据集源自2025年4月发表于《地理学报》的论文成果…...