单例模式的简单理解

单例模式

  • 前言
  • 一、单例模式是什么
  • 二、单例模式的使用
    • 饿汉模式
    • 单线程下的懒汉模式
    • 多线程下的懒汉模式(优化懒汉模式)
      • 加锁
  • 三、总结


前言

设计模式是将一些经典的问题场景进行整合归纳,并提供一些解决方案,相当于一种“套路”。
熟练掌握设计模式,可以提高代码的下限。


一、单例模式是什么

单例模式,简单来说就是单个实例。即在整个进程中的某个类有且只有一个对象

要满足这种条件,需要从根本上保证对象是唯一实例。 只通过人的自我意识是不行的,同时需要通过编码上的技巧使编译器可以检测代码中是否有多个实例。在发现存在多个实例时,计算机会编译出错。

二、单例模式的使用

饿汉模式

饿汉模式是指在运行之后,无论进程是否需要该对象都在最开始的时候创建。

  • 在类Singleton中,首先初始化类对象instance,static成员在类加载的时候初始化。
    当后续需要使用这个类的实例时,就可以调用getInstance方法进行获取了。
  • 同时我们还需要禁止外部代码创建该类的实例,当类之外的代码尝试new的时候,就需要调用构造方法,因此我们将构造方法设为private. 如此依赖在new的时候就会报错。 在这里插入图片描述
class Singleton {private static Singleton instance = new Singleton();private Singleton() {}public static Singleton getInstance() {return instance;}
}

我们可以在main方法中进行判断,结果为true

public static void main(String[] args) {Singleton s1 = Singleton.getInstance();Singleton s3 = Singleton.getInstance();System.out.println(s1 == s3);}

单线程下的懒汉模式

懒汉模式与饿汉模式相反,它不在进程启动时就创建实例,而是在第一次使用的时候才去创建。

  • 与懒汉模式相同,将构造方法设为private防止类之外代码创建新对象

  • 由于初始对象lazy = null 因此在调用getLazy()方法的过程中,需要对lazy对象进行是否非空判断。
    代码示例如下

class SingletonLazy {private static SingletonLazy lazy = null;public static SingletonLazy getLazy() {if (lazy == null) {lazy = new SingletonLazy();}return lazy;}
}

多线程下的懒汉模式(优化懒汉模式)

在多线程中,如果多个线程要同时调用getLazy()方法,又会发生什么问题呢?
我们知道,getLazy()中的指令并不是单个/原子指令的。
多线程中的分析:我们可以通过时间轴进行一个简单的模拟。如图所示,因为线程是并发执行的,当线程A初步进行判断且lazy = null时,线程B将整个方法执行完了,此时lazy != null 。
而线程A的getLazy()方法还没执行完,因此在线程A中又new了一个lazy对象。
于是我们可以想到,通过加锁操作保证线程安全。
在这里插入图片描述

加锁

针对该线程安全问题所进行的加锁操作如下,通过加锁将if和new打包成一个原子操作,如此一来就能解决线程安全问题了。

public static SingletonLazy getLazy() {synchronized (lazy){if (lazy == null) {lazy = new SingletonLazy();}}return lazy;}

在上述代码中,每次调用该类对象都需要进行一次锁操作的判定,一个两个线程还好,如果是多个线程的话,锁判定操作无疑是很消耗cpu资源的。
我们可以再次进行优化。
首先我们初步判断是否要进行加锁操作,如果需要,我们再加锁,若是不需要加锁,就代表着lazy != null 我们就可以直接跳过加锁操作了。
在加入这段代码之后的很长一段时间,lazy对象是非空的,这可能会出现内存可见性的问题,因此我们可以加上volatile解决这个问题。
优化代码如下

class SingletonLazy {//设对象lazy为空private volatile static SingletonLazy lazy = null;public static SingletonLazy getLazy() {if (lazy == null) {//条件判断是否需要加锁 如果lazy= null synchronized (lazy) {if (lazy == null){//条件判断 是否需要newlazy = new SingletonLazy();}}}return lazy;}private SingletonLazy() {}
}

三、总结

饿汉模式为了“急”,在一开始就创建。那么当一个代码中存在多个单例类时,就会导致这些实例在启动时集体创建,会拖慢程序启动时间。
懒汉模式在首次调用时才会创建类对象,如此一来拖慢程序的时间分散,用户难以察觉“卡顿”。
关于内存可见性的文章 ☞内存可见性

关于本文源码 ☞单例模式简单使用

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

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

相关文章

数据仓库介绍_维度表(三)

维度表概述 维度表是维度建模的基础和灵魂。前文提到,事实表紧紧围绕业务过程进行设计,而维度表则围绕业务过程所处的环境进行设计。维度表主要包含一个主键和各种维度字段,维度字段称为维度属性。 表设计步骤 确定维度(表&…

SQL 针对上面的salaries表emp_no字段创建索引idx_emp_no

系列文章目录 文章目录 系列文章目录前言 前言 前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家。点击跳转到网站,这篇文章男女通用,看懂了就去分享给你的码吧。 描述 针对salaries…

【开源合规】开源许可证风险场景详细解读

文章目录 前言关于BlackDuck许可证风险对比图弱互惠型许可证举个例子具体示例LGPL系列LGPL-2.0-onlyLGPL-2.0-or-laterLGPL-2.1-onlyLGPL-2.1-or-laterLGPL-3.0-onlyLGPL-3.0-or-laterMPL系列MPL-1.0MPL-1.1MPL-2.0EPL系列EPL-1.0EPL-2.0互惠型许可证GPL系列GPL-1.0GPL-2.0GPL-…

3.相机标定原理及代码实现(opencv)

1.相机标定原理 相机参数的确定过程就叫做相机标定。 1.1 四大坐标系及关系 (1)像素坐标系(单位:像素(pixel)) 像素坐标系是指相机拍到的图片的坐标系,以图片的左上角为坐标原点&a…

合合信息大模型加速器亮相WAIC大会:文档解析与文本识别新突破

合合信息大模型加速器亮相WAIC大会:文档解析与文本识别新突破 文章目录 合合信息大模型加速器亮相WAIC大会:文档解析与文本识别新突破前言合合信息TextIn平台:智能文档处理的领军者文档解析引擎:百页文档秒级处理大模型的发展背景…

【机器学习】独立成分分析(ICA):解锁信号的隐秘面纱

🌈个人主页: 鑫宝Code 🔥热门专栏: 闲话杂谈| 炫酷HTML | JavaScript基础 ​💫个人格言: "如无必要,勿增实体" 文章目录 独立成分分析(ICA):解锁信号的隐秘面纱引言I…

若依 ruoyi-vue SpringBoot highlight-textarea 输入框敏感词关键词高亮标红(二)

参考文章,非常感谢大佬的分享 实现可高亮的输入框 — HighlightTextarea GitHub:highlight-textarea 可看作者上一篇文章 若依 ruoyi-vue SpringBoot聊天敏感词过滤sensitive-word(一) 效果图 审核时,输入框高亮敏感词&#xff…

vue3 + tsx 表格 Action 单独封装组件用法

前言 先上图看右侧列 action 的 UI 效果: 正常来说,如果一个表格的附带 action 操作,我们一般会放在最右侧的列里面实现,这个时候有些UI 框架支持在 SFC 模板里面定义额外的 solt,当然如果不支持,更通用的…

LabVIEW实现LED显示屏视觉检测

为了满足LED显示屏在生产过程中的严格质量检测需求,引入自动化检测系统是十分必要的。传统人工检测方式存在检测强度高、效率低、准确性差等问题,自动化检测系统则能显著提高检测效率和准确性。视觉检测系统的构建主要包含硬件和软件两个部分。 视觉系统…

新兴市场游戏产业爆发 传音以技术抢抓机遇 ​

随着年轻人口的增加以及互联网的普及,非洲、中东等新兴市场正迎来游戏产业的大爆发,吸引着全球游戏企业玩家在此开疆辟土。中国出海企业代表传音以新兴市场需求为中心,秉持本地化创新理念不断加强游戏等关键领域技术攻关凭借移动终端设备为全球玩家带来极致游戏体验,收获了消费…

谷粒商城实战笔记-26-分布式组件-SpringCloud-Gateway网关核心概念原理

微服务架构中,API网关扮演着至关重要的角色,它不仅作为微服务间的通信桥梁,还负责安全、监控、限流等职责。 一,网关的发展历程 SpringCloud的网关经历了两代的迭代和更替。 第一代网关是早期的Zuul,由 Netflix 开发…

kafka 消费者

消费者 消费者。消费者连接到Kafka上并接收消息,进而进行相应的业务逻辑处理。 消费组 消费者负责订阅Kafka中的主题,并且从订阅的主题上拉取消息。 消费组:每个消费者都有一个对应的消费组,每一个分区只能被一个消费组中的一个…

深入了解Rokid UXR2.0 SDK内置的Unity AR Glass开发组件

本文将了解到Rokid AR开发组件 一、RKCameraRig组件1.脚本属性说明2.如何使用 二、PointableUI组件1.脚本属性说明2.如何使用 三、PointableUICurve组件1.脚本属性说明2.如何使用 四、RKInput组件1.脚本属性说明2.如何使用 五、RKHand组件1.脚本属性说明2.如何使用3.如何禁用手…

昇思25天学习打卡营第17天|基于 MindSpore 实现 BERT 对话情绪识别

基于 MindSpore 实现 BERT 对话情绪识别 BERT介绍 BERT(Bidirectional Encoder Representations from Transformers)是一种基于Transformer架构的预训练语言模型,由谷歌在2018年提出。从以下6个方面来介绍BERT: 1. 预训练和微调&…

Linux C语言基础 day8

目录 思维导图: 学习目标: 学习内容: 1. 字符数组 1.1 二维字符数组 1.1.1 格式 1.1.2 初始化 1.1.3 二维字符数组输入输出、求最值、排序 2. 函数 2.1 概念 关于函数的相关概念 2.2 函数的定义及调用 2.2.1 定义函数的格式 2.3…

GaussDB关键技术原理:高性能(五)

GaussDB关键技术原理:高性能(四)从USTORE存储引擎、计划缓存计划技术、数据分区与分区剪枝、列式存储和向量化引擎、SMP并行执行等五方面对高性能关键技术进行解读,本篇将从LLVM动态查询编译执行、SQL-BYPASS执行优化、线程池化、…

k8s核心操作_Ingress统一网关入口_域名访问配置_ingress域名转发规则配置_根据域名访问不同服务---分布式云原生部署架构搭建026

上一节我们已经把 ingress 安装好了可以看到 kubectl get svc -A 可以看到 出现了ingress-nginx 的service,在ingre-nginx这个命名空间中,有两个,一个是 ingress-nginx-controller 开了两个一个是对应http,一个对应https 一个是 ingress-nginx-controller-admission 对…

14.爬虫---Selenium 经典动态渲染工具的使用

14.Selenium 经典动态渲染工具的使用 1.查看chrome浏览器版本2.ChromeDriver 安装3.Selenium 安装4.验证安装5.基本用法5.1启动浏览器5.2导航到页面5.3查找元素5.3.1单个元素 find_element5.3.2多个元素 find_elements 5.4 执行操作5.5 动作链ActionChains5.6 执行 JavaScript …

修BUG:程序包javax.servlet.http不存在

貌似昨晚上并没有成功在tomcat上面运行,而是直接运行了网页。 不知道为啥又报错这个。。。 解决方案: https://developer.baidu.com/article/details/2768022 就整了这一步就行了 而且我本地就有这个tomcat就是加进去了。 所以说啊,是不是&a…

C语言 | Leetcode C语言题解之第227题基本计算题II

题目&#xff1a; 题解&#xff1a; int calculate(char* s) {int n strlen(s);int stk[n], top 0;char preSign ;int num 0;for (int i 0; i < n; i) {if (isdigit(s[i])) {num num * 10 (int)(s[i] - 0);}if (!isdigit(s[i]) && s[i] ! || i n - 1) {s…