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

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.mzph.cn/news/805398.shtml

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

相关文章

C++23标准库模块

一、C23 标准库引入了两个命名模块&#xff1a;std 和 std.compat&#xff1a; std 导出 C 标准库命名空间 std 中定义的声明和名称&#xff0c;例如 std::vector。 它还会导出 C 包装器标头的内容&#xff0c;例如 <cstdio> 和 <cstdlib>&#xff0c;提供类似 st…

c#获取Web.Config中的值出现的错误及解决办法

c#获取Web.Config中的值出现的错误及解决办法 1.错误提示 2.原因寻找 问题出在Web.Config文件中 <add key"mchid " value"1495103432"/>//mchid 后面不应该有空格图示如下&#xff1a; 3.改正代码如下&#xff1a; <?xml version"1.0…

022——设计通信帧格式

本期没想好怎么排版以流水账形式展示了 int tcp_server(int argc, char *argv[]) {int server_fd, client_fd; struct sockaddr_in server_addr, client_addr; socklen_t client_len sizeof(client_addr); char *ip_address argv[1]; int port atoi(argv[2]); // 创建T…

【Keil5-debug】

Keil5-debug ■ 好的链接■ watch窗口中&#xff0c;变量值不会刷新■ 当选择了非0级优化时■■ ■ 好的链接 参考地址&#xff1a; debug ■ watch窗口中&#xff0c;变量值不会刷新 有时候在watch窗口中&#xff0c;变量值不会刷新&#xff0c;这时候就需要查看一下"…

Capture One 23 Enterprise for Mac中文版 全面的图像处理工具

Capture One 23 Enterprise for Mac中文版一款专业的图像编辑和管理软件&#xff0c;具备强大的功能和工具&#xff0c;适用于摄影师、摄影工作室和专业用户。 软件下载&#xff1a;Capture One 23 Enterprise for Mac中文版下载 该软件为用户提供了全面的图像处理工具&#xf…

SpringCloudAlibaba-整合nacos(二)

目录地址&#xff1a; SpringCloudAlibaba整合-CSDN博客 一、nacos服务部分 1.下载nacos&#xff0c;并执行数据库脚本&#xff1a;nacos-mysql.sql 2.修改配置文件&#xff0c;配置mysql 3.启动nacos ./startup.sh -m standalone 4.访问&#xff1a;http://127.0.0.1:884…

Terraform 扩展

Terraform 扩展 Terraform Meta-Arguments 元参数 count 创建相似的资源for_each 创建相似的资源depends_on 定义资源或者模块的依赖provider 定义provider选项lifecycle 资源的生命周期行为 参数使用范围备注countresource module适用于创建多个相似的资源&#xff0c;使用…

1999-2022年各省研究与试验发展人员全时当量数据/省研发人员全时当量数据/(RD)人员全时当量(无缺失)

1999-2022年各省研究与试验发展人员全时当量数据/省研发人员全时当量数据/(R&D)人员全时当量&#xff08;无缺失&#xff09; 1、时间&#xff1a;1999-2022年 2、来源&#xff1a;科技年鉴 3、指标&#xff1a;研究与试验发展人员全时当量/研发人员全时当量 4、范围&a…

软考-系统集成项目管理中级-新一代信息技术

本章历年考题分值统计 本章重点常考知识点汇总清单(掌握部分可直接理解记忆) 本章历年考题及答案解析 32、2019 年上半年第 23 题 云计算通过网络提供可动态伸缩的廉价计算能力&#xff0c;(23)不属于云计算的特点。 A.虚拟化 B.高可扩展性 C.按需服务 D.优化本地存储 【参考…

Docker快速上手及常用命令速查

Docker快速上手 安装 在ubuntu上安装docker: sudo apt-get install docker docker -v #查看版本在centos7上安装docker&#xff1a;(docker在YUM源的Extras仓库中) yum install docker systemctl start dockerdocker常用命令速查 #查看docker信息 docker info #查看本地镜…

欧拉函数-求解互质数(Java)

欧拉函数 介绍 欧拉函数&#xff08;Eulers Totient Function&#xff09;是一个在数论中非常重要的函数&#xff0c;通常用符号φ(n)表示。对于正整数n&#xff0c;欧拉函数φ(n)定义为小于等于n且与n互质的正整数的个数。 例如&#xff0c;当n8时&#xff0c;与8互质的正整…

万字长文:FineBI面试题及参考答案详解

1:FineBI的基本概念是什么? FineBI是帆软软件有限公司推出的一款商业智能产品。它的核心功能是通过分析企业已有的信息化数据,帮助企业发现并解决存在的问题,预测模拟企业将来的发展,并协助企业及时调整策略做出更好的决策,增强企业的可持续竞争性。 2:描述FineBI的使…

node中可以使用js的三个模块dom,bom,ecmSrimpt吗

在Node.js环境中&#xff0c;不能直接使用浏览器提供的Document Object Model (DOM)和Browser Object Model (BOM)&#xff0c;因为这两个概念是浏览器特有的API集合&#xff0c;它们与浏览器的用户界面、窗口管理、事件处理、文档结构操作等功能紧密关联&#xff0c;专为浏览器…

基于Vue的权限管理方案(大体流程设计)

基于Vue的权限管理方案 在前端开发中&#xff0c;实现权限管理是保障系统安全和数据合规的重要手段之一。基于Vue框架&#xff0c;我们可以设计一套完整的权限管理方案&#xff0c;包括路由级别、片段&#xff08;类似tab切换中的sheet&#xff09;和按钮权限的控制。下面详细…

如何系统地自学Python?一份完整的学习指南

Python 是一种简单而强大的编程语言&#xff0c;被广泛应用于数据科学、人工智能、Web 开发等领域。对于想要自学 Python 的人来说&#xff0c;一个系统化的学习计划是非常重要的。在本文中&#xff0c;我将分享一份完整的学习指南&#xff0c;帮助你系统地自学 Python。 1. 学…

hive 数据库表常用操作及相关函数讲解

创建数据库并指定hdfs存储位置 create database myhive2 location ‘/myhive2’; 使用location关键字&#xff0c;可以指定数据库在HDFS的存储路径。 Hive的库在HDFS上就是一个以.db结尾的目录 默认存储在&#xff1a; /user/hive/warehouse内 当你为Hive表指定一个LOCATION时…

NumPy入门(一)

NumPy入门(一) 工具: jupyter notebook jupyter notebook 功能 : 数据处理 &#xff08;python 处理数据功能&#xff09; coding文字型的描述 富文本 word可视化支持 官网: https://jupyter.org/ 启动命令 jupyter notebook 1.1 numpy简介 Python的拓展库, 提供数据对象 nda…

【数据下载】SODA数据更新至2022并教学下载

【数据下载】SODA数据更新至2022并教学下载 我为什么那么喜欢使用SODA数据&#xff1f; 就是三维网格化的数据&#xff0c;好用。 但是需要高分辨率还是需要找别的。 以前分享过SODA数据下载&#xff0c;但上次版本过于凌乱。因此重新借助更新再分享一次&#xff0c;不为过。…

JavaScript的事件监听

事件监听是计算机编程中的一个重要概念&#xff0c;特别是在图形用户界面&#xff08;GUI&#xff09;编程和网络编程中。它涉及到设置一个或多个监听器&#xff08;也称为事件处理器或回调函数&#xff09;等待特定事件的发生&#xff0c;并在事件发生时执行相应的操作或响应。…