【单例模式】

单例模式是指在内存中只会创建且仅创建一次对象的设计模式。

一、实现方式

1. 饿汉式

 在类加载的时候就创建实例,无论是否使用,实例都会被创建。优点是实现简单,线程安全。缺点是可能造成资源浪费,而程序可能不一定会使用这个实例。

代码示例:

public class Singleton {//创建实例,并且用static保证实例唯一private static final Singleton instance = new Singleton();//把构造方法设置为private,在类外就无法通过new的方式来创建Singleton实例private Singleton() {}//获取实例public static Singleton getInstance() {return instance;}
}


2. 懒汉式写法

public class Singleton {private static Singleton instance = null;private Singleton() {}public static synchronized Singleton getInstance() {if (instance == null) {instance = new Singleton();}return instance;}
}

说明:在第一次调用获取实例方法时才创建实例。

思考:上述写的饿汉模式懒汉模式,在多线程环境中是否安全呢?为什么?

分析饿汉模式:

饿汉模式,只涉及到读操作,因此,在多线程环境中是线程安全的。

分析懒汉模式:

懒汉模式,涉及到了读和写操作,会出现脏读的情况,因此,懒汉模式不是线程安全的。 

如图所示:

通过加锁改进刚才代码:

public class Singleton {private static Singleton instance = null;private Singleton() {}public static Singleton getInstance() {synchronized (Singleton.class) {if (instance == null) {instance = new Singleton();}}return instance;}
}

说明如下图所示:

刚才代码还有缺陷:分析代码:

public static Singleton getInstance() {synchronized (Singleton.class) {if (instance == null) {instance = new Singleton();}}return instance;}

思考: 

如果每次调用getInstance方法的时候,都会进行加锁操作,加锁操作是有性能开销的,真的需要每次都进行加锁吗?

分析:这里的加锁在new出对象之前加上是有必要的,但是,一旦对象new完了,后续调用getInstance方法,此时instance的值一定是非空的,就会触发return。

解决方案:加上一个条件判断,如果对象没有创建才加锁,否则就return。

代码示例:

public class Singleton {private static volatile Singleton instance;private Singleton() {}public static Singleton getInstance() {//这个条件判断的作用是:是否要加锁if (instance == null) {  synchronized (Singleton.class) {//这个条件判断的作用是:是否要创建对象if (instance == null) {instance = new Singleton();}}}return instance;}
}

你以为就完了吗?

上述代码当中还存在内存可见性和指令重排序的问题。

分析:假设现在有很多线程去调用getInstance方法,只有第一次读的时候才去读内存,后续都是读寄存器或者缓存(此时有如果发生了写操作,其他线程,或者处理器是感知不到的)就会发生内存可见性问题。

指令重排序问题本质上就是编译器或者处理器优化。

instance = new Singleton();这条语句拆分成三个步骤:

1:申请内存空间

2:调用构造方法,把这个内存空间初始化成一个合理的对象

3: 把内存空间的地址赋值给instance引用

 在正常情况下是按照 1 2 3这个顺序去执行,此时此刻,编译器为了提高程序的执行效率,有可能把这个1 2 3 的执行顺序优化成 1 3 2或者其他情况。

如图所示:

 volatile来解决内存可见性和指令重排序问题:

代码示例:

public class Singleton {//volatile来解决内存可见性和指令重排序问题//static实例唯一,共享private static volatile Singleton instance;//禁止外部new对象private Singleton() {}public static Singleton getInstance() {//这个条件判断的作用是:是否要加锁if (instance == null) {  synchronized (Singleton.class) {//这个条件判断的作用是:是否要创建对象if (instance == null) {instance = new Singleton();}}}return instance;}
}


3. 静态内部类方式

利用类加载机制实现延迟加载,只有在调用获取实例的方法时,才会加载静态内部类,从而创建实例。线程安全,并且实现简单高效。

public class Singleton {private Singleton() {}private static class SingletonHolder {private static final Singleton INSTANCE = new Singleton();}public static Singleton getInstance() {return SingletonHolder.INSTANCE;}
}

4. 枚举方式

简洁且线程安全。

public enum SingletonEnum {INSTANCE;public void doSomething() {// 具体方法实现}
}

二、单例模式的优点

1. 减少系统资源开销:避免了频繁创建和销毁对象带来的资源浪费。

2. 保证对象的唯一性:确保在整个应用程序中只有一个实例存在,方便对这个实例进行统一的管理和控制。

3. 方便资源访问:提供了一个全局访问点,可以方便地获取这个唯一的实例,而不需要在多个地方传递实例对象。

三、单例模式的使用场景

1. 日志记录器:通常整个应用程序只需要一个日志记录器实例,以确保所有的日志信息都被记录到同一个地方。

2. 数据库连接池:管理数据库连接,避免频繁地创建和销毁连接,提高性能。

3. 配置文件读取:应用程序通常只需要一个配置文件读取实例,以确保配置信息的一致性。


 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.xdnf.cn/news/1556758.html

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

大数据新视界 --大数据大厂之大数据于基因测序分析的核心应用 - 洞悉生命信息的密钥

💖💖💖亲爱的朋友们,热烈欢迎你们来到 青云交的博客!能与你们在此邂逅,我满心欢喜,深感无比荣幸。在这个瞬息万变的时代,我们每个人都在苦苦追寻一处能让心灵安然栖息的港湾。而 我的…

第三届图像处理、计算机视觉与机器学习国际学术会议(ICICML 2024)

目录 重要信息 大会简介 组织单位 大会成员 征稿主题 会议日程 参会方式 重要信息 大会官网:www.icicml.org 大会时间:2024年11月22日-24日 大会地点:中国 深圳 大会简介 第三届图像处理、计算机视觉与机器学…

最强AI绘画大模型Flux可以在SDWebUI 上使用了!超便捷的Flux模型使用教程!AI绘画零基础入门到实战教程

大家好,我是画画的小强 目前最强的AI绘画大模型Flux.1 横空出世有段时间了,模型效果也得到了广泛的认可,但是 Stable Diffusion WebUI 官方迟迟没有跟进,据说是因为要修改很多底层的处理机制,加之ComfyUI如火如荼&…

C++读取大文件三种方法速度比较

目录 测试说明第一种方法:按块读,一次读8kb第二种方法:按行读,一次读一行第三种方法:多线程并行读取完整示例 测试说明 测试文件:100万行,每一行是两个小数,中间用逗号隔开&#xf…

LeetCode讲解篇之377. 组合总和 Ⅳ

文章目录 题目描述题解思路题解代码题目链接 题目描述 题解思路 总和为target的元素组合个数 可以由 总和为target - nums[j]的元素组合个数 转换而来,其中j为nums所有元素的下标 而总和target - nums[j]的元素组合个数 可以由 总和为target - nums[j] - nums[k]的…

谁喝酒 1.3.0 | 这款聚会游戏完全免费,无需注册登录,简洁易用。

适合聚会时玩的游戏APP,完全免费,无需注册登录。 大小:36M 百度网盘:https://pan.baidu.com/s/1nkUi4W3UhMyEsnAiSoOP9g?pwdolxt 夸克网盘:https://pan.quark.cn/s/239397c0c894 移动网盘:https://caiyun…

【英语】4. 熟词僻义

文章目录 前言e.g.总结参考文献 前言 进行英语前后缀的复习 e.g. spell: 咒语 时期want: povertyaddress: 强调,地址,演讲bear: stand, endureblow: blast ,冲击chair: 主席的位置 ,掌管 chair a company fuel: add 燃料&#x…

融乐·Music 1.1.3 | 专为音乐爱好者打造,海量免费音乐资源

融乐Music提供了海量免费音乐资源,满足各种类型的音乐需求。界面简洁,操作方便,支持在线播放和离线下载。 大小:13.6M 百度网盘:https://pan.baidu.com/s/1AVKX747bvteAcO__3o1KCQ?pwdolxt 夸克网盘:http…

【含开题报告+文档+PPT+源码】基于SSM框架的线上交易商城的设计与实现

开题报告 随着互联网的快速发展,电子商务成为了现代化社会中不可或缺的一部分。线上交易平台的兴起,为商家和消费者创造了更多的交易机会和便利。然而,传统的电商平台通常由一家中央机构管理和控制,对商家和消费者的自由度有一定…

JWT集成Keycloak

一、直接使用现有域账号、密码获取token方式 1.KeyClack 使用现有配置 Client id : account-console 2.服务配置文件配置 3.API接口配置 4. 获取token 5.调用方式(Swagger)(代码方式直接在请求头加上token) 5.1 配置在Swagger访问 5.2 访问需要认证的接…

【JavaEE初阶】深入理解线程池的概念以及Java标准库提供的方法参数分析

前言 🌟🌟本期讲解关于MySQL索引事务,希望能帮到屏幕前的你。 🌈上期博客在这里:【JavaEE初阶】多线程案列之定时器的使用和内部原码模拟-CSDN博客 🌈感兴趣的小伙伴看一看小编主页:GGBondlctrl…

Python酷库之旅-第三方库Pandas(134)

目录 一、用法精讲 601、pandas.DataFrame.plot.pie方法 601-1、语法 601-2、参数 601-3、功能 601-4、返回值 601-5、说明 601-6、用法 601-6-1、数据准备 601-6-2、代码示例 601-6-3、结果输出 602、pandas.DataFrame.plot.scatter方法 602-1、语法 602-2、参数…

【C++】入门基础介绍(下)输入输出,函数重载,缺省与引用

文章目录 7. C输入与输出8. 缺省参数9. 函数重载10. 引用10. 1 引用的概念10. 2 引用的特性10. 3 引用的使用10. 4 const引用10. 5 指针和引用的关系 11. inline12. nullptr 7. C输入与输出 iostream是 Input Output Stream 的缩写,是标准输入、输出流库&#xff0…

BFS解决最短路问题_最小基因变化、单词接龙_C++

BFS解决最短路问题_最小基因变化、单词接龙_C 1. 题目解析2. 算法分析3. 代码实现4. 举一反三:单词接龙 1. 题目解析 leetcode链接:https://leetcode.cn/problems/minimum-genetic-mutation/submissions/569463000/ 基因序列可以表示为一条由 8 个字符组…

【计算机网络】面试必问TCP十大机制

1. TCP协议的报文格式 说明: TCP 报文格式主要分为两部分:TCP 报文头部和数据部分。以下是对各字段的详细解释: TCP 报文头部 源/目的端口:各占用16位。表示数据从哪个进程发送,发送到哪个进程去。序号字段&#xff1a…

千古风流人物 陆游

简介 陆游(1125年-1210年),字务观,号放翁,越州山阴(今浙江绍兴)人,南宋诗人、词人。后人每以陆游为南宋诗人之冠。是中国南宋时期的著名文学家、词人、政治家和军事家。 陆游出生在…

基于SpringBoot+Vue+MySQL的药品信息管理系统

系统展示 管理员界面 医生界面 员工界面 系统背景 随着医疗技术的不断提升,药品在治疗疾病中扮演着越来越重要的角色。传统的药品管理方式以人工方式为主,但人工管理难以满足现代社会快速发展的需求。因此,需要一种更加高效、便捷的信息化管理…

FLORR.IO画廊(2)

指南针(超级) 是Florr.io的一种辅助花瓣,用于指示超级生物的位置。 基础(超级) 是florr.io的一种攻击型花瓣,玩家在初次游玩时即获得5个基本,个数不随着等级改变而改变,基本不可合成…

C++之模版进阶篇

目录 前言 1.非类型模版参数 2.模版的特化 2.1概念 2.2函数模版特化 2.3 类模板特化 2.3.1 全特化和偏特化 2.3.2类模版特化应用实例 3.模版分离编译 3.1 什么是分离编译 3.2 模板的分离编译 3.3 解决方法 4. 模板总结 结束语 前言 在模版初阶我们学习了函数模版和类…