【面试八股总结】单例模式实现详解

一、基本概念

        单例设计模式是⼀种确保⼀个类只有⼀个实例,并提供⼀个全局访问点来访问该实例的创建模式。

关键概念:

  • 一个私有构造函数:确保只能单例类自己创建实例
  • 一个私有静态变量:确保只有一个实例,私有静态变量用于保存该类的唯一实例
  • 一个公有静态函数:给使用者提供调用方法

优点:

        有些实例全局只需要⼀个,使用单例模式就可以避免一个全局使用的类,频繁的创建与销毁,耗费系统资源。

二、实现方法

单例模式有两种类型:

  • 懒汉式:在真正需要使用对象时,采取创建该单例类对象
  • 饿汉式:在类加载时已经创建好该单例对象,等待被程序使用

1. 懒汉式(线程不安全)

        懒汉式创建对象方法在程序使用前会先判断该对象是否已经实例化(判断是否为空),若已实例化直接返回该类对象,否则执行实例化。

class Singleton{private static Singleton instance;private Singleton(){}    // 构造函数为私有,确保外界不可以使用new创建该类实例public static Singleton GetInstance(){    // 该方法为本类实例的唯一全局访问点if (instance == NULL){         // 若实例不存在,则new一个实例,否则返回已有实例instance = new Singleton();}return instance;}
};

2. 懒汉式(线程安全) 

        在这里考虑线程安全问题,如果多个线程同时判断instance为空,那么他们都会去实例化一个Singleton对象,就违背了单例模式的原则。为了保证线程安全,考虑加上锁。

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

3. 双重检查锁

        上述代码虽然解决了线程安全问题,但是性能降低了。因为,即使实例已经实例化了, 但是锁还在,每次还是只能拿到锁的线程进入该方法使线程阻塞,等待时间过长。

        将锁的位置改变,并且多加了⼀个检查。也就是,先判断实例是否已经存在,若已经存在了,则不会执行判断方法内的有锁方法了。 而还没有实例化的时候多个线程进去也没有事,因为里面的方法有锁,只会让⼀个线程进⼊最内层方法并实例化实例。如此⼀来,最多也就是第⼀次实例化的时候,会有线程阻塞的情况,后续便不会再有线程阻塞的问题。

class Singleton{private volatile static Singleton uniqueInstance;private Singleton(){}  public static Singleton getInstance() {if (uniqueInstance== NULL) {    synchronized(Singleton.class) {    // 加锁,只有一个线程获得该锁并进行初始化if (uniqueInstance== NULL) {         uniqueInstance= new Singleton();}}}return uniqueInstance;}
}

为什么使用volatile关键字修饰uniqueInstance变量?

uniqueInstance= new Singleton();

上述一行代码在执行时分为三步:

  1. 为uniqueInstance分配空间;
  2. 初始化uniqueInstance;
  3. 将uniqueInstance指向分配的内存地址。

        采用volatile会禁止JVM的指令重排(指令重排会导致有些协程获取到还没有初始化的实例),保证多线程环境下的安全运行。

4. 饿汉式

        饿汉式在类加载时已经创建好该对象,在程序调用时直接返回该单例对象即可,即:在编码时已经指明马上创建该对象,不需要等待调用时再创建。

class Singleton{private static final Singleton instance= new Singleton();private Singleton(){}public static Singleton getInstance(){return instance;}
}; 

5. 静态内部类

        当外部类Singleton被加载时,静态内部类SingletonHolder并没有被加载金内存,当调用getInstance()方法时,才会触发SingletonHolder.instance,此时静态内部类才会被加载进内存,并且初始化instance实例。该方法延迟了实例化,节约了资源,且线程安全,性能也提高了。

class Singleton{private Singleton(){}    // 静态内部类持有实例private static class SingletonHolder{private static final Singleton instance = new Singleton();}// 公告静态方法,返回实例public static Singleton getInstance(){return SingletonHolder.instance;}
}; 

6. 枚举类

        默认枚举实例的创建就是线程安全的,且在任何情况下都是单例。可以防止调用者使用反射、序列化与反序列化机制强制生成多个单例对象,破坏单例模式。

public enum Singleton{INSTANCE;// 可以添加其他方法和属性public void doSomething(){// 实现...}
}

总结:

(1)单例模式常见的写法有两种:懒汉式、饿汉式

  • 懒汉式:在需要用到对象时才实例化对象,正确的实现方式是:Double Check + Lock,解决了并发安全和性能低下问题
  • 饿汉式:在类加载时已经创建好该单例对象,在获取单例对象时直接返回对象即可,不会存在并发安全和性能问题。

(2)在开发中如果对内存要求非常高,那么使用懒汉式写法,可以在特定时候才创建该对象;

        如果对内存要求不高使用饿汉式写法,因为简单不易出错,且没有任何并发安全和性能问题

(3)为了防止多线程环境下,因为指令重排序导致变量报NPE,需要在单例对象上添加volatile关键字防止指令重排序

(4)最优雅的实现方式是使用枚举,其代码精简,没有线程安全问题,且 Enum 类内部防止反射和反序列化时破坏单例。

三、应用场景

单例设计模式适用于以下⼀些场景:

  • 资源共享:当多个模块或系统需要共享某⼀资源时,可以使用单例模式确保该资源只被创建⼀次,避免重复创 建和浪费资源。
  • 控制资源访问:单例模式可以用于控制对特定资源的访问,例如数据库连接池、线程池等。
  • 配置管理器:当整个应用程序需要共享⼀些配置信息时,可以使用单例模式将配置信息存储在单例类中,方便全局访问和管理。
  • 日志记录器:单例模式可以用于创建⼀个全局的日志记录器,用于记录系统中的日志信息。
  • 线程池:在多线程环境下,使用单例模式管理线程池,确保线程池只被创建⼀次,提高线程池的利⽤率。
  • 缓存:单例模式可以⽤于实现缓存系统,确保缓存只有⼀个实例,避免数据不⼀致性和内存浪费。

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

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

相关文章

4-4 词嵌入技术(word2vec)

4-4 词嵌入技术(word2vec) 词嵌入技术(word2vec)是自然语言处理(NLP)中的一种关键技术,通过将词语映射到低维向量空间中,使得计算机能够理解和处理语言中的语义信息。词嵌入不仅可以…

【性能测试】第一节.性能测试基础

文章目录 前言一、性能测试概述二、常见的性能测试指标 2.1 并发 2.2 响应时间 2.3 事务 2.4 点击率 2.5 吞吐量 2.6 资源利用率三、性能测试的分类 3.1 一般性能测试 3.2 负载测试 3.3 压力测试 3.4 稳定性测试总结 前言 一…

CAS详解

文章目录 CAS使用示例Unsafe类实现原理CAS问题 CAS CAS全称为Compare and Swap被译为比较并交换,是一种无锁算法。用于实现并发编程中的原子操作。CAS操作检查某个变量是否与预期的值相同,如果相同则将其更新为新值。CAS操作是原子的,这意味…

【错题集-编程题】栈和排序(栈 + 贪心)

牛客对于题目连接:栈和排序_牛客题霸_牛客网 (nowcoder.com) 一、分析题目 每次尽可能的先让当前需要的最大值弹出去。 二、代码 // 修改后的代码 class Solution { public:/*** 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方…

【2024_CUMCM】Matlab快速入门

目录 常识 disp and input 字符串合并 sum 提取矩阵指定位置的元素 指定行列 指定行or指定列(返回行/列向量) 指定某些行 指定全部元素,按列拼接 size repmat 矩阵的运算 基本运算 形状相同的矩阵运算 每个元素同时和常数相乘或相…

C++相关概念和易错语法(19)(继承规则、继承下的构造和析构、函数隐藏)

1.继承规则 继承的本质是复用,是结构上的继承而不是内容上的继承,近似于在子类中声明了父类的成员变量。 (1)写法:class student : public person 派生类(子类),继承方式&…

泛二级泛目录多模板程序程序(泛目录和二级目录的区别)

泛解析站群_优化网站排名吸引百度蜘蛛必备程序主要功能: 1、网站支持无限生成页面不存在死链的风险每个也是不是网站栏目就是文章内容! 2、支持域名泛解析绑定,每个二级域名都是一个独立的 3、支持百度自动提交收录,每天随机自动提交无限自己…

echarts图表:类目轴

category 类目轴,适用于离散的类目数据。 例如商品名称、时间等。 类目轴上的每个刻度代表一个类目,刻度之间没有量的关系,只是简单的分类。 在类目轴上,数据点会对应到相应的类目上。

运行前端项目提示 run `npm fund` for details,如何解决?

经常出现在前端的一个小坑,分享一下技巧。 运行npm install命令终端提示: 107 packages are looking for funding run npm fund for details 解决方案: npm install --no-fund

Linux 进程 PID 管理

文章目录 1. 前言2. 进程 PID 相关数据结构3. 进程 PID 的构建3.1 第一个进程 PID 构建3.2 第二个进程 PID 的构建过程3.2.1 从当前进程复制进程 PID 信息3.2.2 创建每进程的 PID 管理数据 (struct pid) 并初始化3.2.3 绑定进程和其相关的 PID 管理数据 3.3 进程的 PID 建立过程…

【Oracle】实验三 Oracle数据库的创建和管理

【实验目的】 掌握Oracle数据库的创建方法使用DBCA创建数据库在数据库中装入SCOTT用户及其表 【实验内容】 使用DBCA创建数据库,名为MYDB,找到其初始化文件(文本型和服务器型文件都要找到),查看各类默认位置并记录下来(包括物理文件所在目…

LINUX系统编程:基于环形队列和信号量的生产者消费者模型

目录 1.环形队列 2.加上信号量的理解 3.代码 1.环形队列 环形队列使用vector封装出来的。 环形队列可以实现并发生产和消费,就是在消费的同时也可以生产。 这个是建立在生产者消费者位置不重合的情况下。 因为位置重合之后,环形队列为空或者满&#xf…

Linux DRM 那些事 - HDMI 接口 DTS 配置

本文基于RockPI 4A单板Debian系统 Linux 4.4 内核介绍DRM框架HDMI接口DTS配置。 在DTS中主要实现:HDMI的使能、VOP绑定、IOMUX引脚配置和HDMI控制器配置。 一、HDMI 配置 文件:arch/arm64/boot/dts/rockchip/rk3399-rock-pi-4.dtsi #include "rk3…

C++ 宏

C中的宏是一种预处理指令,用于在编译时将代码中的标识符替换为指定的文本。 #define 指令 1.无参宏定义 无参宏的宏名后不带参数。 其定义的一般形式为: #define 标识符 字符串 其中的“#”表示这是一条预处理命令。凡是以“#”开头的均为预处理命…

LLM 合成数据生成完整指南

大型语言模型是强大的工具,不仅可以生成类似人类的文本,还可以创建高质量的合成数据。这种能力正在改变我们进行 AI 开发的方式,特别是在现实世界数据稀缺、昂贵或隐私敏感的情况下。在本综合指南中,我们将探索 LLM 驱动的合成数据…

C语言——流程控制:if...else、switch...case

控制类语句: 逻辑运算符: 选择语句: if...else: if()括号内的内容终究会被转换成0,1,满足的话即为1,不满足的话为0。因此要注意,()括号内因为条件…

简单实现一个本地ChatGPT web服务(langchain框架)

简单实现一个本地ChatGPT 服务,用到langchain框架,fastapi,并且本地安装了ollama。 依赖安装: pip install langchain pip install langchain_community pip install langchain-cli # langchain v0.2 2024年5月最新版本 pip install bs4 pi…

ChatGPT摆脱“AI味”:全面提升写作质感

ChatGPT在各种写作、创作场景都发挥了很大的价值,即使中文语料库占比不到5%,也能生成流畅的中文文本。但随着使用的深入,大家也逐渐发现了机器生成的内容,往往带有一种僵硬、刻板的“AI味”,尤其在论文、自媒体写作中&…

算法力扣刷题记录 四十三【最大、最小深度问题】

前言 本文学习树的深度问题:二叉树(N叉树)最大深度、最小深度; 记录 三十九【层序遍历模版应用二】中解决过二叉树的最大深度和最小深度题目。思路是按层遍历: 最大深度,相当于层序遍历结束;…

ZBLOG程序怎么天收录?本人亲自试过请看以下教程(zblog怎么样)

您为管理员组,请查看下方隐藏内容! 先去ZBLOG官网下载ZBLOG程序 直达地址https://www.zblogcn.com/ 安装到宝塔里 安装好了之后打开zblog的后台 点开应用中心搜索CMS自适应资讯主题免费 安装即可 安装了之后配置主题内容 有经验者可以去吧动态改成…