单例模式基本介绍及两种实现方式详解

news/2024/5/3 5:07:04/文章来源:https://blog.csdn.net/ling_zu_qi/article/details/137381796

1. 什么是单例模式

1.1 什么是模式

        这里所说的模式,指的是代码的设计模式,这属于程序猿的高阶技能.对于普通的程序猿,写出来的代码没有bug,能跑就行,不用过多地在乎,实际上也很难去设计代码的模式.                                              但是有些大佬对这一方面十分得心应手,能够将具体的代码抽象为一种模式,让其他程序猿照着这个模式写代码就可以了,属实是造福他人.

1.2 什么是单例模式

        单例模式是设计模式的一种,我们约定在单例模式中类实例化出的对象只能存在一个,也就是说每当我们要去获取这个类实例的时候,无论获取多少次,什么时候获取,获取到的类实例必须是同一个.

1.3 为什么要使用单例模式

        有的读者可能会思考:为什么我们一定要使用单例模式呢?我多创建几个实例,我只用一个不行吗?实际上,这样的想法没有什么问题.

但是,存在即合理,不要忘了,我们创建一个实例是需要消耗时间和空间资源的,现在我们这个类中没有放很多成员变量/方法,但是试想一下,如果这个实例中存放了百万条数据,我们创建一个实例需要的资源开销就大了!!!在这种情况下,我们还能心中毫无波澜地创建一个个实例吗?显然是不可以的.

2. 单例模式的两种设计方法

对于单例模式来说,有许多设计方式,我们这里只介绍两种:饿汉模式和懒汉模式

2.1 饿汉模式

实例创建时机

啥叫饿汉?就是饿到一有吃的就抢着开吃,体现一种"迫不及待"的感觉.我们刚才提到单例模式中只能有一个类的实例,针对饿汉模式,就是在加载类的时候(main线程中代码还未开始执行)直接创建出实例.

如何保证实例的唯一性

这里提供了一个private修饰的构造方法,确保外部代码无法调用这个构造方法,导致在new一个实例时就会编译报错.

对应代码:
class Singleton{private static Singleton instance = new Singleton();public Singleton getInstance(){return instance;}private Singleton(){}
}

2.2 懒汉模式

实例创建时机

啥叫懒?我想许多读者肯定认为懒时一个贬义词,但是我们思考一下:是不是人类为了懒而创造出了许多东西,推动了科技的进步与时代的发展.在计算机中,懒是一个褒义词,是"高效"的代名词.那么对应懒汉模式来说,啥时候创建这样一个类实例呢?

因为"懒",所以在要使用时我再创建;如果一直不用,我就一直不创建.

这样我们也可以满足只创建一个类实例的条件,其他部分其实同饿汉模式没有很大的区别,我们这里直接给出代码

对应代码:
class SingletonLazy {public static SingletonLazy instance = null;public SingletonLazy getInstance() {if(instance==null) {instance = new SingletonLazy();}return instance;}private SingletonLazy() {}
}

3. 线程安全问题分析

在上述两种模式中,我们可以分析一下其中存在的线程安全问题:

对于饿汉模式,其实并不会存在线程安全问题,因为在饿汉模式中,类实例创建的时机是在java进程启动时(此时还没有开始执行main线程),因此即使是在多线程,也不会创建多个类实例十分安全.

但是,在懒汉模式中,可能会存在线程安全问题:

3.1 可能创建多个实例

因为是在多线程环境下,不同线程可能创建了多个类的实例,对于这个问题以及它的解决方法我们十分熟悉,只要加锁就可以了.于是,改进后的代码如下:

class SingletonLazy {public static SingletonLazy instance = null;public Object locker = new Object();public SingletonLazy getInstance() {synchronized (locker) {if(instance==null) {instance = new SingletonLazy();}return instance;}}private SingletonLazy() {}
}
3.2 可能进行错误判断

先问大家一个问题,在单线程中,连续两次条件一样的if判断得到的结果是不是一样的?这不用思考,结果必定是一样的.但是,在多线程环境下,两次看似一样的if判断中间隔着的也许就是"沧海桑田",因此为了保险起见,我们需要进行双重if判断.

双重if加在锁里吗?当然不是.是一层if加在锁外,一层if加在锁里.改进后的代码如下:

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

3.3 可能发生指令重排序

也就是instance这个引用的对象可能在还没有被赋值时(默认的引用对象为null),被其他的线程错误判断,从而创建一个类实例,这也会导致创建多个类实例.我们可以使用volatile修饰instance,来解决这个问题.关于指令重排序详细介绍可以看上一篇博客-->引发线程安全问题的原因及解决方法-CSDN博客

这里给出最终的代码:

class SingletonLazy {public static volatile SingletonLazy instance = null;public Object locker = new Object();public SingletonLazy getInstance() {if(instance==null) {synchronized (locker) {if(instance==null) {instance = new SingletonLazy();}}}return instance;}private SingletonLazy() {}
}

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

如若内容造成侵权/违法违规/事实不符,请联系dt猫网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Unity核心学习

目录 认识模型的制作流程模型的制作过程 2D相关图片导入设置图片导入概述纹理类型设置纹理形状设置纹理高级设置纹理平铺拉伸设置纹理平台打包相关设置 SpriteSprite Editor——Single图片编辑Sprite Editor——Multiple图片编辑Sprite Editor——Polygon图片编辑SpriteRendere…

深度解析SPARK的基本概念

关联阅读博客文章: 深入理解MapReduce:从Map到Reduce的工作原理解析 引言: 在当今大数据时代,数据处理和分析成为了企业发展的重要驱动力。Apache Spark作为一个快速、通用的大数据处理引擎,受到了广泛的关注和应用。…

条件变量的使用(golang)

1、背景 最近在学习go的一个开源协程池,在源码中有用到锁、信号量,锁相对来说用的是比较多的,信号量相对用的较少,之前研究学习过c的std::condition_variable,其实和golang的大同小异,个人感觉c的略强…

面试算法-171-翻转二叉树

题目 给你一棵二叉树的根节点 root ,翻转这棵二叉树,并返回其根节点。 示例 1: 输入:root [4,2,7,1,3,6,9] 输出:[4,7,2,9,6,3,1] 解 class Solution {public TreeNode invertTree(TreeNode root) {if (root n…

绿联 安装火狐浏览器(Firefox),支持访问路由器

绿联 安装火狐浏览器(Firefox),支持访问路由器 1、镜像 linuxserver/firefox:latest 前置条件:动态公网IP。 已知问题: 直接输入中文时,不能完整输入,也可能输入法无法切换到中文,可…

栈与队列2s总结(不含单调栈)

6.栈与队列 栈与队列理论基础 队列是先进先出,栈是先进后出。 C中stack 是容器么? 我们使用的stack是属于哪个版本的STL? 我们使用的STL中stack是如何实现的? stack 提供迭代器来遍历stack空间么? 栈和队列是STL…

ORCAL SQLPLUS上机6-1

SQL> declare2 v_num number:9;3 begin4 v_num:v_num1;5 dbms_output.put_line(v_num);6 end;7 / --定义记录类型,类似结构体,用select...into --定义记录类型,类似结构体,用select...into SQL> declaretype employe…

test4111

欢迎关注博主 Mindtechnist 或加入【Linux C/C/Python社区】一起学习和分享Linux、C、C、Python、Matlab,机器人运动控制、多机器人协作,智能优化算法,滤波估计、多传感器信息融合,机器学习,人工智能等相关领域的知识和…

5分钟了解清楚【osgb】格式的倾斜摄影数据metadata.xml有几种规范

数据格式同样都是osgb,不同软件生产的,建模是参数不一样,还是有很大区别的。尤其在应用阶段。 本文从建模软件、数据组织结构、metadata.xml(投影信息)、应用几个方面进行了经验性总结。不论您是初步开始建模&#xf…

【QT+QGIS跨平台编译】175:【QGIS_App跨平台编译】—【错误处理:未定义的class APP_EXPORT】

点击查看专栏目录 文章目录 一、未定义的class APP_EXPORT二、错误处理 一、未定义的class APP_EXPORT 报错信息: 二、错误处理 第18行增加: #include "qgis_app.h"

文章解读与仿真程序复现思路——电力系统自动化EI\CSCD\北大核心《新型电力系统多阶段输-储协同分布鲁棒规划》

本专栏栏目提供文章与程序复现思路,具体已有的论文与论文源程序可翻阅本博主免费的专栏栏目《论文与完整程序》 论文与完整源程序_电网论文源程序的博客-CSDN博客https://blog.csdn.net/liang674027206/category_12531414.html 电网论文源程序-CSDN博客电网论文源…

Adobe After Effects 2024 v24.3 macOS 视频合成及特效制作软件 兼容 M1/M2/M3

Adobe After Effects 是一款适用于视频合成及特效制作软件,是制作动态影像设计不可或缺的辅助工具,是视频后期合成处理的专业非线性编辑软件。 macOS 12.0及以上版本可用 应用介绍 Adobe After Effects简称 AE 是一款适用于视频合成及特效制作软件,是制作动态影像设计不可或缺…

计算分数和-第12届蓝桥杯选拔赛Python真题精选

[导读]:超平老师的Scratch蓝桥杯真题解读系列在推出之后,受到了广大老师和家长的好评,非常感谢各位的认可和厚爱。作为回馈,超平老师计划推出《Python蓝桥杯真题解析100讲》,这是解读系列的第48讲。 计算分数和&#…

STM32 H7系列学习笔记

必备的API知识 第 1 步:系统上电复位,进入启动文件 startup_stm32h743xx.s,在这个文件里面执行复位中断服务程序。 在复位中断服务程序里面执行函数 SystemInit,在system_stm32h7xx.c 里面。*之后是调用编译器封装好的函数&…

Kubesphere 在 devops 部署项目的时候下载 maven 依赖卡住

Kubesphere 在 devops 部署项目的时候下载 maven 依赖卡住 我下载 下面这段 maven 依赖一直卡住&#xff1a; <build><plugins><plugin><groupId>org.jacoco</groupId><artifactId>jacoco-maven-plugin</artifactId><version>…

LeetCode 80—— 删除有序数组中的重复项 II

阅读目录 1. 题目2. 解题思路3. 代码实现 1. 题目 2. 解题思路 让 index指向删除重复元素后数组的新长度&#xff1b;让 st_idx 指向重复元素的起始位置&#xff0c;而 i 指向重复元素的结束位置&#xff0c;duplicate_num代表重复元素的个数&#xff1b;一段重复元素结束后&am…

Java Web-分层解耦

三层架构 当我们所有代码都写在一起时&#xff0c;代码的复用性差&#xff0c;并且难以维护。就像我们要修改一下服务端获取数据的方式&#xff0c;从文本文档获取改为到数据库中获取&#xff0c;就难以修改&#xff0c;而使用三层架构能很好的解决这个问题。 controller: 控…

PHP 中的 $2y$10,PHP 字符串加密函数 password_hash

PHP 用户密码加密函数 password_hash 自PHP5.5.0之后&#xff0c;新增加了密码散列算法函数(password_hash)&#xff0c;password_hash() 使用足够强度的单向散列算法创建密码的散列 Hash。 password_hash() 兼容 crypt()。 所以&#xff0c; crypt() 创建的密码散列也可用于 …

flask 访问404

当你的项目有自己的蓝图&#xff0c;有添加自己的前缀&#xff0c;也注册了蓝图。 在访问的路由那里也使用了自己的蓝图&#xff0c;如下图 然后你访问的地址也没问题&#xff0c;但是不管怎么样访问就是返回404&#xff0c;这个时候不要怀疑你上面的哪里配置错误&#xff0c;…

【网站项目】校园二手交易平台小程序

&#x1f64a;作者简介&#xff1a;拥有多年开发工作经验&#xff0c;分享技术代码帮助学生学习&#xff0c;独立完成自己的项目或者毕业设计。 代码可以私聊博主获取。&#x1f339;赠送计算机毕业设计600个选题excel文件&#xff0c;帮助大学选题。赠送开题报告模板&#xff…