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

单例模式.

目录

♫什么是单例模式

♫饿汉式单例模式

♫懒汉式单例模式

♫单例模式的线程安全问题

♪原子性

♪内存可见性与指令重排序


♫什么是单例模式

单例模式是一种设计模式,通过巧用Java的现有语法,实现一个只能被创建一个实例的类,并提供一个全局访问点。在有些创场景中,一些特点的类只能创建一个实例,虽然不依赖单例模式我们也可以控制类的实现个数,但通过单例模式实现的类就相当于有了语法约束,即使想要实现多个实例都很难。在Java中,单例模式的实现有多种方式,下面是两种比较常用的实现方式。

♫饿汉式单例模式

饿汉式单例模式是指在类加载时就创建实例对象,通过static关键字保证在程序的整个生命周期中只存在一个实例对象:

public class Singleton {// 静态成员变量,用来记录唯一实例private static Singleton uniqueInstance = new Singleton();// 私有构造方法,防止外部通过new关键字创建实例private Singleton() {}// 静态工厂方法,返回唯一实例public static Singleton getInstance() {return uniqueInstance;}
}

通过将构造方法设置为私有的,保证类外无法通过new来创建实例的同时,通过static将uniqueInstance成员属性修饰为类属性(Java代码中的每个类在编译完成后都会生成.class文件,JVM加载时通过读取.class文件中的二进制指令来在内存中构造出类对象(Singleton.class),类对象的属性就是类属性),由于类对象只有一份,故类属性也就只有一份。

♫懒汉式单例模式

懒汉式单例模式是指在第一次访问时才创建实例对象,在第一次访问之前则不创建对象:

public class Singleton {// 静态成员变量,用来记录唯一实例private static Singleton uniqueInstance = null;// 私有构造方法,防止外部通过new关键字创建实例private Singleton() {}// 静态工厂方法,返回唯一实例public static synchronized Singleton getInstance() {if (uniqueInstance == null) {uniqueInstance = new Singleton();}return uniqueInstance;}
}

懒汉模式与饿汉模式的区别在于懒汉模式只有在第一次使用时才创建实例对象,不使用则不创建实例对象,而饿汉模式则不管有没有使用都会在使用前(类加载时)创建一个实例对象。

♫单例模式的线程安全问题

在多线程环境下,饿汉模式只有到读操作不需要考虑线程安全问题,而懒汉模式既有读又有写,这就得涉及到线程安全了。

1.在if语句中可以分为读、比较、写三步,由于这三步骤不是原子性的,在多线程环境下就可能发生第一个线程读完还未写入前,第二个线程也开始读,从而导致可能多次执行new操作。

♪原子性

我们可以通过synchronized来保证读、比较、写的原子性:

//懒汉模式
class Singleton2 {private static Singleton2 uniqueInstance = null;public Singleton2 getInstance() {synchronized (Singleton2.class) {if (uniqueInstance == null) {uniqueInstance = new Singleton2();}}return uniqueInstance;}private Singleton2() {}
}

虽然通过给类对象加锁保证了if语句的原子性,但这样写每一次使用都需要进行加锁操作加大了开销,故我们还可以在加锁前再判断下需不需要进行加锁操作:

//懒汉模式
class Singleton2 {private static Singleton2 uniqueInstance = null;public Singleton2 getInstance() {if (uniqueInstance == null) {synchronized (Singleton2.class) {if (uniqueInstance == null) {uniqueInstance = new Singleton2();}}}return uniqueInstance;}private Singleton2() {}
}

注:第一个if判断是否需要加锁,第二个if判断是否需要创建对象

♪内存可见性与指令重排序

懒汉模式不仅有原子性问题还有内存可见性与指令重排序的隐患:

♩内存可见性:在多线程环境下,有多个线程同时进行getInstance操作,有可能编译器只有第一次是从内存中读取uniqueInstance的值,其它时候都是直接从寄存器或cache中读取uniqueInstance的值,也会导致多次创建实例对象。

♩指令重排序:uniqueInstance=new Singleton2()操作可以拆分为三步:①.申请内存空间②.调用构造方法在内存空间上创建一个实例对象③.把内存空间的值赋值给uniqueInstance。正常情况下顺序执行①②③是没有问题的,但无法保证编译器不会优化这三步骤的执行顺序,若是执行顺序为①③②,那么就可能在一个线程执行到②之前就调度去另一个线程执行①,这就会导致内存空间后面被初始化,而该线程就以为对象创建好了,如果这时候这个线程使用对象的属性方法就会出现问题。

解决内存可见性与指令重排序就需要给uniqueInstance加上volatile关键字:

//懒汉模式
class Singleton2 {private static volatile Singleton2 uniqueInstance = null;public Singleton2 getInstance() {if (uniqueInstance == null) {synchronized (Singleton2.class) {if (uniqueInstance == null) {uniqueInstance = new Singleton2();}}}return uniqueInstance;}private Singleton2() {}
}

相关文章:

单例模式.

目录 ♫什么是单例模式 ♫饿汉式单例模式 ♫懒汉式单例模式 ♫单例模式的线程安全问题 ♪原子性 ♪内存可见性与指令重排序 ♫什么是单例模式 单例模式是一种设计模式,通过巧用Java的现有语法,实现一个只能被创建一个实例的类,并提供一个全…...

2023年MathorCup高校数学建模挑战赛大数据挑战赛赛题浅析

比赛时长为期7天的妈杯大数据挑战赛如期开赛,为了帮助大家更好的选题,首先给大家带来赛题浅析,为了方便大家更好的选题。 赛道 A:基于计算机视觉的坑洼道路检测和识别 A题,图像处理类题目。这种题目的难度数模独一档…...

c++小惊喜——stringstream

当需要读取一行字符串时&#xff0c;我们通常会有将这个字符串分开的想法 #include<iostream> #include<sstream> using namespace std;int main() {string str;getline(cin, str);stringstream ssin(str);string s[10];int cnt 0;while (ssin >> s[cnt]) …...

ubuntu 18.04 编译安装flexpart 10.4(2023年) —— 筑梦之路

2023年10月29日 环境说明 操作系统版本&#xff1a;ubuntu 18.04 python版本&#xff1a;3.6.9 gcc版本&#xff1a;7.5.0 编译安装路径&#xff1a;/usr/local cmake: 3.10.2 所需要的源码包我已经打包放到我的资源。 2021年1月份已经写过一篇Ubuntu 编译安装的帖子F…...

深度学习(生成式模型)——DDIM:Denoising Diffusion Implicit Models

文章目录 前言为什么DDPM的反向过程与前向过程步数绑定DDIM如何减少DDPM反向过程步数DDIM的优化目标DDIM的训练与测试 前言 上一篇博文介绍了DDIM的前身DDPM。DDPM的反向过程与前向过程步数一一对应&#xff0c;例如前向过程有1000步&#xff0c;那么反向过程也需要有1000步&a…...

HashMap的遍历方式 -- 好几次差点记不起来总结了一下

public class HashMapDemo {public static void main(String[] args) {// 创建一个HashMap并添加一些键值对Map<String, Integer> hashMap new HashMap<>();hashMap.put("Alice", 25);hashMap.put("Bob", 30);hashMap.put("Charlie"…...

PostgreSQL 两表关联更新sql

PostgreSQL两表关联更新SQL如下&#xff1a; UPDATE user SET username ft.name, age ft.age FROM userinfo WHERE user.id ft.id; user 要更新的表 userinfo数据来源表...

R2R 的一些小tip

批次间控制器(Run-to-run Controller)&#xff0c;以应对高混合生产的挑战。将最优配方参数与各种工业特征相关联的模型是根据历史数据离线训练的。预测的最优配方参数在线用于调整工艺条件。 批次控制(R2R control)是一种先进的工艺控制技术&#xff0c;可在运行(如批次或晶圆…...

UML中类之间的六种主要关系

UML中类之间的六种主要关系: 继承&#xff08;泛化&#xff09;&#xff08;Inheritance、Generalization&#xff09;, 实现&#xff08;Realization&#xff09;&#xff0c;关联&#xff08;Association)&#xff0c;聚合&#xff08;Aggregation&#xff09;&#xff0c;组…...

机器学习-朴素贝叶斯之多项式模型

多项式模型&#xff1a; 记住一定用于离散的对象&#xff0c;不能是连续的 于高斯分布相反&#xff0c;多项式模型主要适用于离散特征的概率计算&#xff0c;切sklearn的多项式模型不接受输入负值 因为多项式不接受负值的输入&#xff0c;所以样本数据的特征为数值型数据&…...

下载的nginx证书转换成tomcat证书格式

1、下载的nginx证书格式 XXX.crt private.key 2、转换成JKS格式证书步骤 #crt格式证书转pem openssl x509 -in xxx.crt -out xxx.pem#先转成p12格式&#xff0c;此时注意&#xff0c;如果有别名&#xff0c;需要设置 openssl pkcs12 -export -in xxx.crt -inkey private.key…...

计算机毕业设计选题推荐-社区志愿者服务微信小程序/安卓APP-项目实战

✨作者主页&#xff1a;IT毕设梦工厂✨ 个人简介&#xff1a;曾从事计算机专业培训教学&#xff0c;擅长Java、Python、微信小程序、Golang、安卓Android等项目实战。接项目定制开发、代码讲解、答辩教学、文档编写、降重等。 ☑文末获取源码☑ 精彩专栏推荐⬇⬇⬇ Java项目 Py…...

ES6中数值扩展

目录 二进制和八进制表示法 Number.isFinite() Number.isNaN() Number.parseInt()和Number.parseFloat() Number.isInteger() Math.trunc() Math.sign() Math.cbrt()&#xff1a; Math.clz32()&#xff1a; Math.imul()&#xff1a; Math.fround()&#xff1a; ES6中…...

sql-50练习题11-15

sql-50练习题11-15 前言数据库表结构介绍学生表课程表成绩表教师表 1-1 查询没有学全所有课程的同学的信息1-2 查询至少有一门课与学号为01的同学所学相同的同学的信息1-3 查询和1号的同学学习的课程完全相同的其他同学的信息1-4 查询没学过张三老师讲授的任一门课程的学生姓名…...

【多线程面试题十九】、 公平锁与非公平锁是怎么实现的?

文章底部有个人公众号&#xff1a;热爱技术的小郑。主要分享开发知识、学习资料、毕业设计指导等。有兴趣的可以关注一下。为何分享&#xff1f; 踩过的坑没必要让别人在再踩&#xff0c;自己复盘也能加深记忆。利己利人、所谓双赢。 面试官&#xff1a; 公平锁与非公平锁是怎么…...

3.4每日一题(变量可分离方程通解)

...

LabVIEW背景颜色设为和其他程序或图像中一样

LabVIEW背景颜色设为和其他程序或图像中一样 有时候LabVIEW背景色要和其他程序或者图片的颜色保持一致&#xff0c;如果要求不高可以大致设置一下。如果要求较高&#xff0c;那可以按照如下的方式。 先用PS打开标准图像&#xff0c;之后用吸管工具选择图像上中的点&#xff0…...

图表参考线,数据对比一目了然_三叠云

参考线 路径 仪表盘 >> 仪表盘设计 功能简介 新增「参考线」功能。 参考线是在单个图表组件中添加的一条水平虚线&#xff0c;也可以配置两条线形成的参考区间&#xff0c;它表示该水平线上纵坐标值的大小。 使用场景&#xff1a; 通过辅助线的设置&#xff0c;可…...

【深度学习】Transformer、GPT、BERT、Seq2Seq什么区别?

请看vcr&#xff1a;https://transformers.run/back/transformer/...

数据结构与算法之LRU: 实现 LRU 缓存算法功能 (Javascript版)

关于LRU缓存 LRU - Lease Recently Used 最近使用 如果内存优先&#xff0c;只缓存最近使用的&#xff0c;删除 ‘沉睡’ 数据 核心 api: get set 分析 使用哈希表来实现, O(1)必须是有序的&#xff0c;常用放在前面&#xff0c;沉睡放在后面, 即&#xff1a;有序&#xff0…...

OpenLayers 可视化之热力图

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

反向工程与模型迁移:打造未来商品详情API的可持续创新体系

在电商行业蓬勃发展的当下&#xff0c;商品详情API作为连接电商平台与开发者、商家及用户的关键纽带&#xff0c;其重要性日益凸显。传统商品详情API主要聚焦于商品基本信息&#xff08;如名称、价格、库存等&#xff09;的获取与展示&#xff0c;已难以满足市场对个性化、智能…...

Vue2 第一节_Vue2上手_插值表达式{{}}_访问数据和修改数据_Vue开发者工具

文章目录 1.Vue2上手-如何创建一个Vue实例,进行初始化渲染2. 插值表达式{{}}3. 访问数据和修改数据4. vue响应式5. Vue开发者工具--方便调试 1.Vue2上手-如何创建一个Vue实例,进行初始化渲染 准备容器引包创建Vue实例 new Vue()指定配置项 ->渲染数据 准备一个容器,例如: …...

从零实现STL哈希容器:unordered_map/unordered_set封装详解

本篇文章是对C学习的STL哈希容器自主实现部分的学习分享 希望也能为你带来些帮助~ 那咱们废话不多说&#xff0c;直接开始吧&#xff01; 一、源码结构分析 1. SGISTL30实现剖析 // hash_set核心结构 template <class Value, class HashFcn, ...> class hash_set {ty…...

【Java_EE】Spring MVC

目录 Spring Web MVC ​编辑注解 RestController RequestMapping RequestParam RequestParam RequestBody PathVariable RequestPart 参数传递 注意事项 ​编辑参数重命名 RequestParam ​编辑​编辑传递集合 RequestParam 传递JSON数据 ​编辑RequestBody ​…...

SpringCloudGateway 自定义局部过滤器

场景&#xff1a; 将所有请求转化为同一路径请求&#xff08;方便穿网配置&#xff09;在请求头内标识原来路径&#xff0c;然后在将请求分发给不同服务 AllToOneGatewayFilterFactory import lombok.Getter; import lombok.Setter; import lombok.extern.slf4j.Slf4j; impor…...

初学 pytest 记录

安装 pip install pytest用例可以是函数也可以是类中的方法 def test_func():print()class TestAdd: # def __init__(self): 在 pytest 中不可以使用__init__方法 # self.cc 12345 pytest.mark.api def test_str(self):res add(1, 2)assert res 12def test_int(self):r…...

HashMap中的put方法执行流程(流程图)

1 put操作整体流程 HashMap 的 put 操作是其最核心的功能之一。在 JDK 1.8 及以后版本中&#xff0c;其主要逻辑封装在 putVal 这个内部方法中。整个过程大致如下&#xff1a; 初始判断与哈希计算&#xff1a; 首先&#xff0c;putVal 方法会检查当前的 table&#xff08;也就…...

在Ubuntu24上采用Wine打开SourceInsight

1. 安装wine sudo apt install wine 2. 安装32位库支持,SourceInsight是32位程序 sudo dpkg --add-architecture i386 sudo apt update sudo apt install wine32:i386 3. 验证安装 wine --version 4. 安装必要的字体和库(解决显示问题) sudo apt install fonts-wqy…...

Java + Spring Boot + Mybatis 实现批量插入

在 Java 中使用 Spring Boot 和 MyBatis 实现批量插入可以通过以下步骤完成。这里提供两种常用方法&#xff1a;使用 MyBatis 的 <foreach> 标签和批处理模式&#xff08;ExecutorType.BATCH&#xff09;。 方法一&#xff1a;使用 XML 的 <foreach> 标签&#xff…...