【JavaEE】——单例模式引起的多线程安全问题:“饿汉/懒汉”模式,及解决思路和方法(面试高频)
阿华代码,不是逆风,就是我疯,你们的点赞收藏是我前进最大的动力!!希望本文内容能够帮助到你!
目录
一:单例模式(singleton)
1:概念
二:“饿汉模式”
1:前引
2:代码编译
3:代码分析
4:解释为什么叫“饿汉模式”
三:“懒汉”模式
1:前引
2:代码编译
3:代码分析
4:“懒汉”的优点
5:比较“饿汉”和“懒汉”
四:“饿汉”模式线程安全问题
五:“懒汉”模式的线程安全问题
1:重复创建实例
2:解决问题
(1)解决思路的核心本质:
(2)缺点:
①效率降低:
②不可预期:
3:优化效率问题
(1)问题解释
(2)解决方法
六:指令重排序问题
前引:
1:代码拆分三指令
2:分析
3:代码解释
4:解锁思路
(1)复习volatile两个功能
一:单例模式(singleton)
1:概念
单例模式就是,在java进程中,要求指定的类,只能有一个对象
我们通过一些特殊的技巧来确保,我们的实例(对象)只有一个——换句话说,就是如果我们尝试new多个实例,编译器就会报错。
二:“饿汉模式”
1:前引
(1)知识科普
我们先认识俩个单词——singleton(单例模式)和getInstance(获取实例)
(2)每个类只能有一个类对象,比如Thread类,Thread.class(获取到Thread这个类的类对象)它是从.class文件加载到内存当中的
2:代码编译
package thread;/*** Created with IntelliJ IDEA.* Description:* User: Hua YY* Date: 2024-09-24* Time: 13:20*/
class Singleton{private static Singleton instance = new Singleton();public static Singleton getInstance(){//返回值类型为Singletonreturn instance;}private Singleton(){//静态构造方法让你访问不到}}
public class ThreadDemon28 {//“饿汉模式”public static void main(String[] args) {Singleton s1 = Singleton.getInstance();Singleton s2 = Singleton.getInstance();System.out.println(s1 == s2);//判断s1和s2是否指向的是同一个对象}
}

3:代码分析


最后我们在main方法中比较s1,s2获取到的地址是否相同(s1,s2所指向的对象)
4:解释为什么叫“饿汉模式”
因为我们在类加载的时候就创建了这个实例,(初始化静态成员变量),这个时机非常的早——相当于程序一启动,实例就创建好了。所以就用“饿汉”来形容创建实例非常的迫切非常早
三:“懒汉”模式
1:前引
“懒汉”模式相对于“饿汉”模式不同的地方在于创建实例的时机更加晚一些,下面我们通过代码来进行展示
2:代码编译
package thread;/*** Created with IntelliJ IDEA.* Description:* User: Hua YY* Date: 2024-09-24* Time: 13:52*/
class SingletonLazy{private static SingletonLazy instance = null;public static SingletonLazy getInstance(){if (instance == null){ //如果instance为null,则进入if创建实例,创建实例的时机是第一次调用getInstance这个方法instance = new SingletonLazy();}return instance;//第二次第三次调用getInstance()这个方法,就不会进入if语句中,而直接返回instance了}private SingletonLazy(){}
}
public class ThreadDemon29 {public static void main(String[] args) {SingletonLazy s1 = SingletonLazy.getInstance();SingletonLazy s2 = SingletonLazy.getInstance();System.out.println(s1 == s2);}}

3:代码分析
很明显的不同是,初始,instance初始化为null,并没有实例化对象,只有第一次调用了getInstance方法后才会实例化SingletonLazy
4:“懒汉”的优点
例如现在有一个非常大的文件(1个G)
“饿汉”模式会直接把一个G全部加载到内存中,在进行展示。
“懒汉”模式会先加载100kb的数据到内存中,随着用户的翻页,在逐步的加载到内存当中
5:比较“饿汉”和“懒汉”
(1)创建时机上“饿汉”更早
(2)“饿汉”创建实例依赖于程序驱动,“懒汉”创建实例依赖于调用方法
四:“饿汉”模式线程安全问题

对于饿汉模式,无论有多少个线程在调用getInstance 方法,都会返回instance,对于return这一条代码来说,只有一个“读操作”,线程是非常安全的
五:“懒汉”模式的线程安全问题
1:重复创建实例
①看下面这个例子,我们拆分if里面的代码,会发现实例被new了两次,这就不是单例模式了,就有bug了
②有人说:不就是多new了个对象嘛,问题不大~~~。但是对于单例模式来说,一个对象可能要管理10GB的内存,或者更大,多new一个对象,就多翻了一倍的内存啊!!

2:解决问题
想办法给if条件和创建实例进行打包——用关键字synchronized。
(1)解决思路的核心本质:
是让,if语句打包成一个整体,成为“原子性操作”
(2)缺点:
①效率降低:
以下加锁的思路有一个致命缺点,我们保证多线程下我们创建出来的实例就只有一个是通过“加锁”和“解锁”来解决的,但是这个过程很耗费资源
②不可预期:
一旦线程发生了阻塞,那么什么时候解除阻塞我们是不可控制和预期的


3:优化效率问题
(1)问题解释

(2)解决方法
六:指令重排序问题
前引:
指令重排序是编译器优化的一种方式,调整原有代码的执行顺序,保证逻辑不变的前提下,提高程序的效率
![]()
1:代码拆分三指令
上面这段代码可以分为三个指令来执行
①申请一段内存空间 (买房子)
②在这段内存上,调用构造方法,初始化实例 (给房子装修)
③把内存地址赋值给instance (拿到房子的钥匙)
package thread;/*** Created with IntelliJ IDEA.* Description:* User: Hua YY* Date: 2024-09-24* Time: 13:52*/
class SingletonLazy{private static Object locker1 = new Object();private static SingletonLazy instance = null;public static SingletonLazy getInstance(){if (instance == null){synchronized(locker1){if (instance == null){ //如果instance为null,则进入if创建实例,创建实例的时机是第一次调用getInstance这个方法instance = new SingletonLazy();}}}return instance;//第二次第三次调用getInstance()这个方法,就不会进入if语句中,而直接返回instance了}private SingletonLazy(){}
}
public class ThreadDemon29 {public static void main(String[] args) {SingletonLazy s1 = SingletonLazy.getInstance();SingletonLazy s2 = SingletonLazy.getInstance();System.out.println(s1 == s2);}}
2:分析
我们延用上面的代码
上述三个指令的执行顺序可以为①②③,也可以为①③②
问题出现在如果执行顺序为①③②上

3:代码解释
线程t1经过代码优化后,先执行③赋值地址,此时instance只是接收了一个地址,它所指向的是一个尚未被初始化的对象,这个对象啥也不是,可以理解成“全为0”
恰巧此时线程t2插入,进入if条件判断,判断instance != null,线程t2以为实例已经创建完毕,直接return instance,假设t2紧接着调用instance里面的方法或者属性,就会出现大问题。
4:解锁思路
加入关键字volatile
(1)复习volatile两个功能
①保证内存可见性(即每次访问变量都要重新读取内存,而不会优化到寄存器或者缓存当中)
②禁止指令重排序

此时针对变量的读写操作,就不会出现重排序的问题了
相关文章:
【JavaEE】——单例模式引起的多线程安全问题:“饿汉/懒汉”模式,及解决思路和方法(面试高频)
阿华代码,不是逆风,就是我疯,你们的点赞收藏是我前进最大的动力!!希望本文内容能够帮助到你! 目录 一:单例模式(singleton) 1:概念 二:“饿汉模…...
huggingface实现中文文本分类
目录 1 自定义数据集 2 分词 2.1 重写collate_fn方法 3 用BertModel加载预训练模型 4 模型试算 5 定义下游任务 6 训练 7 测试 #导包 import torch from datasets import load_from_disk #用于加载本地磁盘的datasets文件 1 自定义数据集 #自定义数据集 #…...
基于python+控制台+txt文档实现学生成绩管理系统(含课程实训报告)
目录 第一章 需求分析 第二章 系统设计 2.1 系统功能结构 2.1.1 学生信息管理系统的七大模块 2.1.2 系统业务流程 2.2 系统开发必备环境 第三章 主函数设计 3.1 主函数界面运行效果图 3.2 主函数的业务流程 3.3 函数设计 第四章 详细设计及实现 4.1 学生信息录入模块的设计与实…...
Spring Boot 整合MyBatis-Plus 实现多层次树结构的异步加载功能
文章目录 1,前言2,什么是多层次树结构?3,异步加载的意义4,技术选型与实现思路5,具体案例5.1,项目结构5.2,项目配置(pom.xml)5.3,配置文件…...
网络工程师指南:防火墙配置与管理命令大全,零基础入门到精通,收藏这一篇就够了
本指南详细介绍了防火墙的配置与管理命令,涵盖了防火墙的工作原理、常见配置命令、安全策略与访问控制、日志管理与故障排查,并通过实战案例展示了如何有效防御网络攻击。通过学习本指南,网络工程师能够系统掌握防火墙的配置与管理技能&#…...
英特尔终于找到了Raptor Lake处理器崩溃与不稳定问题的根源
技术背景 在过去的几个月里,一些用户报告称他们的第13代和第14代Intel Core“Raptor Lake”处理器遇到了系统崩溃和不稳定的情况。这些问题最初在2024年7月底被英特尔识别出来,并且初步的诊断显示,这些问题与微码有关,该微码使CP…...
Shp2pb:Shapefile转Protocol Buffers的高效工具
Shp2pb是一个实用工具,专门用于将Shapefile(shp)格式转换为Protocol Buffers(protobuf)文件。这对于以更高效、更紧凑的方式处理地理数据特别有用。以下是关于如何安装和使用Shp2pb工具的详细说明,以及一个…...
Elasticsearch使用Easy-Es + RestHighLevelClient实现深度分页跳页
注意!!!博主只在测试环境试了一下,没有发到生产环境跑。因为代码还没写完客户说不用弄了( •̩̩̩̩_•̩̩̩̩ ) 也好,少个功能少点BUG 使用from size的时候发现存在max_result_window10000的限制&…...
基于ASRPRO的语音应答
做这个的起因是为了送女朋友,而且这东西本身很简单,所以在闲暇之余尝试了一下。 这个工程很简单,只通过对ASRPRO进行编程即可。 先看效果。(没有展示所有效果,后续会列出来所有对话触发) 语音助手示例1 语音助手示例2 代码部分使用天文Block编辑,找了一圈好像只…...
3D看车汽车案例,车模一键换皮肤,开关车门,轴距,电池功能
3D 汽车案例 网址: http://car.douchuanwei.com/...
数据结构-4.栈与队列
本篇博客给大家带来的是栈和队列的知识点, 其中包括两道面试OJ题 用队列实现栈 和 用栈实现队列. 文章专栏: Java-数据结构 若有问题 评论区见 欢迎大家点赞 评论 收藏 分享 如果你不知道分享给谁,那就分享给薯条, 如果分享不成功, 那我就会回你一下,那样你就分享成功啦. 你们的…...
芝士AI写作有什么特色? 大模型支撑,智能改写续写,让写作更轻松
又到了一年的毕业季,大学四年眨眼间匆匆就过去了,毕业,求职,考研,工作,升学,但是在这之前,我们必须要完成论文的写作,这也是每一位大学生都必须要面对~ 芝士AI官网&…...
【计网】从零开始学习http协议 --- http的请求与应答
如果你不能飞,那就跑; 如果跑不动,那就走; 实在走不了,那就爬。 无论做什么,你都要勇往直前。 --- 马丁路德金 --- 从零开始学习http协议 1 什么是http协议2 认识URL3 http的请求和应答3.1 服务端设计…...
记录linux环境下搭建本地MQTT服务器实现mqtt的ssl加密通讯
1、ubuntu安装mosquitto sudo apt-get update//安装服务端 sudo apt-get install mosquitto//安装客户端 sudo apt-get install mosquitto-clients 2、安装openssl 3、mqtts/tls加密传输 mosquitto原生支持了TLS加密,TLS(传输层安全)是SSL&…...
基于python+django+vue的电影数据分析及可视化系统
作者:计算机学姐 开发技术:SpringBoot、SSM、Vue、MySQL、JSP、ElementUI、Python、小程序等,“文末源码”。 专栏推荐:前后端分离项目源码、SpringBoot项目源码、Vue项目源码、SSM项目源码 精品专栏:Java精选实战项目…...
HJ50-四则运算:栈的运用、中缀表达式转后缀表达式并计算结果
文章目录 题目一、分析1.1表达式预处理1.2中缀表达式转后缀1.3 后缀表达式计算结果 二、答案 题目 一、分析 通过利用栈将中缀表达式转换为后缀表达式,在根据后缀表达式计算运算结果。由于包含负数操作数的情况,并且操作数位数不固定为1,因此…...
C++编程:实现简单的高精度时间日志记录小程序
0. 概述 为了检查是否存在系统时间跳变,本文使用C实现了一个简单的高精度时间日志记录小程序。该程序能够每隔指定时间(默认40毫秒)记录一次系统时间到文件中,并具备以下功能: 自定义时间间隔和文件名:通…...
QQ机器人搭建
使用QQ官方机器人Python SDK和三方框架搭建QQ群聊机器人 文章目录 使用QQ官方机器人Python SDK和三方框架搭建QQ群聊机器人前言编写机器人代码机器人监听群聊进行文字回复机器人监听群聊进行图片回复机器人监听群聊进行文件发送机器人监听群聊进行视频发送机器人监听群聊进行语…...
flink设置保存点和恢复保存点
增加了hdfs package com.qyt;import org.apache.flink.api.java.functions.KeySelector; import org.apache.flink.api.java.tuple.Tuple2;import org.apache.flink.runtime.state.storage.FileSystemCheckpointStorage;import org.apache.flink.streaming.api.datastream.Dat…...
使用python获取百度一下,热搜TOP数据详情
一、查找对应链接 # 警告:以下代码仅供学习和交流使用,严禁用于任何违法活动。 # 本代码旨在帮助理解和学习编程概念,不得用于侵犯他人权益或违反法律法规的行为。 1、打开百度页面 百度一下,你就知道 2、点击F12 或 右键鼠标…...
系统设计 --- MongoDB亿级数据查询优化策略
系统设计 --- MongoDB亿级数据查询分表策略 背景Solution --- 分表 背景 使用audit log实现Audi Trail功能 Audit Trail范围: 六个月数据量: 每秒5-7条audi log,共计7千万 – 1亿条数据需要实现全文检索按照时间倒序因为license问题,不能使用ELK只能使用…...
HTML 列表、表格、表单
1 列表标签 作用:布局内容排列整齐的区域 列表分类:无序列表、有序列表、定义列表。 例如: 1.1 无序列表 标签:ul 嵌套 li,ul是无序列表,li是列表条目。 注意事项: ul 标签里面只能包裹 li…...
LLM基础1_语言模型如何处理文本
基于GitHub项目:https://github.com/datawhalechina/llms-from-scratch-cn 工具介绍 tiktoken:OpenAI开发的专业"分词器" torch:Facebook开发的强力计算引擎,相当于超级计算器 理解词嵌入:给词语画"…...
AI,如何重构理解、匹配与决策?
AI 时代,我们如何理解消费? 作者|王彬 封面|Unplash 人们通过信息理解世界。 曾几何时,PC 与移动互联网重塑了人们的购物路径:信息变得唾手可得,商品决策变得高度依赖内容。 但 AI 时代的来…...
10-Oracle 23 ai Vector Search 概述和参数
一、Oracle AI Vector Search 概述 企业和个人都在尝试各种AI,使用客户端或是内部自己搭建集成大模型的终端,加速与大型语言模型(LLM)的结合,同时使用检索增强生成(Retrieval Augmented Generation &#…...
【笔记】WSL 中 Rust 安装与测试完整记录
#工作记录 WSL 中 Rust 安装与测试完整记录 1. 运行环境 系统:Ubuntu 24.04 LTS (WSL2)架构:x86_64 (GNU/Linux)Rust 版本:rustc 1.87.0 (2025-05-09)Cargo 版本:cargo 1.87.0 (2025-05-06) 2. 安装 Rust 2.1 使用 Rust 官方安…...
比较数据迁移后MySQL数据库和OceanBase数据仓库中的表
设计一个MySQL数据库和OceanBase数据仓库的表数据比较的详细程序流程,两张表是相同的结构,都有整型主键id字段,需要每次从数据库分批取得2000条数据,用于比较,比较操作的同时可以再取2000条数据,等上一次比较完成之后,开始比较,直到比较完所有的数据。比较操作需要比较…...
LangFlow技术架构分析
🔧 LangFlow 的可视化技术栈 前端节点编辑器 底层框架:基于 (一个现代化的 React 节点绘图库) 功能: 拖拽式构建 LangGraph 状态机 实时连线定义节点依赖关系 可视化调试循环和分支逻辑 与 LangGraph 的深…...
Canal环境搭建并实现和ES数据同步
作者:田超凡 日期:2025年6月7日 Canal安装,启动端口11111、8082: 安装canal-deployer服务端: https://github.com/alibaba/canal/releases/1.1.7/canal.deployer-1.1.7.tar.gz cd /opt/homebrew/etc mkdir canal…...
raid存储技术
1. 存储技术概念 数据存储架构是对数据存储方式、存储设备及相关组件的组织和规划,涵盖存储系统的布局、数据存储策略等,它明确数据如何存储、管理与访问,为数据的安全、高效使用提供支撑。 由计算机中一组存储设备、控制部件和管理信息调度的…...

