单例模式的简单理解

单例模式

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


前言

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


一、单例模式是什么

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

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

二、单例模式的使用

饿汉模式

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

  • 在类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){
                //条件判断 是否需要new
                    lazy = new SingletonLazy();
                }
            }
        }
        return lazy;
    }

    private SingletonLazy() {

    }
}

三、总结

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

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

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

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

相关文章

政企单位光纤资源高效管理与优化策略

引言 随着信息技术的飞速发展,政企单位对于通信基础设施的管理要求日益提高。然而,传统的管理模式,如Excel表格记录和纸质审批流程,已难以满足当前复杂多变的业务需求。在此背景下,我们实施了光纤管理的数字化转型项目…

LLMs的基本组成:向量、Tokens和嵌入

编者按:随着人工智能技术的不断发展,大模型(语言、视觉,或多模态模型)已成为当今AI应用的核心组成部分。这些模型具有处理和理解自然语言等模态输入的能力,推动了诸如聊天机器人、智能助手、自动文本生成等…

防火墙安全策略练习

实验拓扑 实验要求 1.DMZ区内的服务器,办公区仅能在办公时间内(9:00 — 18:00)可以访问,生产区的设备全天可以访问 2.生产区不允许访问互联网,办公区和游客区允许访问互联网 3.办公区设备10.…

C++初学者指南-5.标准库(第一部分)--顺序视图

C初学者指南-5.标准库(第一部分)–顺序视图 文章目录 C初学者指南-5.标准库(第一部分)--顺序视图std::string_view (C17)避免不必要的内存分配类似字符串的函数参数创建string_viewsstring_view接口 std::span (C20)作为参数(主要用例&#x…

笔记本硬盘数据恢复的6种方法!简单易懂

可以从笔记本电脑硬盘恢复已删除的数据吗? “我不小心删除了笔记本电脑硬盘上的重要数据。请问我可以在笔记本电脑硬盘上恢复已删除的数据吗?如果可以,我应该怎么做才能恢复数据呢?” 很多笔记本电脑用户可能会不小心地从电脑中…

翻译|解开LLMs的神秘面纱:他们怎么能做没有受过训练的事情?

大语言模型(LLMs)通过将深度学习技术与强大的计算资源结合起来,正在彻底改变我们与软件互动的方式。 虽然这项技术令人兴奋,但许多人也担忧LLMs可能生成虚假的、过时的或有问题的信息,他们有时甚至会产生令人信服的幻…

顶顶通呼叫中心中间件-打电话没声音检查步骤(mod_cti基于FreeSWITCH)

顶顶通呼叫中心中间件-电话没声音检查步骤(mod_cti基于FreeSWITH) 检查步骤 1、检查配置文件 检查配置文件:打开ccadmin -> 配置文件 -> vars -> external_ip$${local_ip_v4}看一下这个有没有配置正确的外网IP,如果没有配置正确就需要配置正…

方格验证码输入框实现方式

引言 在实际开发过程中验证码输入框是一个很常见UI界面。通常来讲有简单的输入框,也有方格的输入框,其中相对较为棘手就是这种方格输入框里面还需要显示光标的情况。本篇博客我们就来主要讨论一下方格带光标的验证码输入框样式。 实现方案 在着手实现…

顺序结构 ( 六 ) —— 顺序结构实例 【互三互三】

🚀欢迎互三👉:程序猿方梓燚 💎💎🚀所属专栏:C教程💎 🚀关注博主,后期持续更新系列文章 🚀如果有错误感谢请大家批评指出,及时修改 &am…

什么是RLHF(基于人类反馈的强化学习)?

什么是RLHF(基于人类反馈的强化学习)? 基于人类反馈的强化学习(Reinforcement Learning from Human Feedback, RLHF)是一种结合强化学习和人类反馈的技术,用于训练智能体,使其行为更符合人类期…

农牧行业CRM洞察:打造营、销、服一体化数字营销平台

01、行业应用背景 保持企业活力,支撑业务单元协调发展,稳定核心产品竞争力,将成为农牧行业企业数字化、数智化建设的指导方向。 积极发挥数据在生产、流通、消费各个环节的决策支撑,为农牧企业特别是多业态集团型企业&#xff0…

1.浅谈蓝牙BLE的总体框架

这里只展开BLE这一部分, 框图如下所示 蓝牙也是使用分层的结构组织代码。 Application:是自己的业务逻辑实现的地方。当然应用程序需要根据BLE的规定,实现配置文件(profile)、服务(service)和…

【话题】开源项目:从边缘到主流的转变之旅

目录 开源项目有哪些机遇与挑战? 前言 宏观视角:开源项目的发展趋势 开源运动,作为一股不可忽视的创新力量,正在重塑全球科技版图。其核心价值在于打破知识的壁垒,推动技术的民主化,让信息与技术不再为少…

C++ :内联函数inline|nullptr

欢迎来到HarperLee的学习笔记! 博主主页传送门:HarperLee博客主页! 欢迎交流学习! 一、inline关键字 1.1 什么是内联函数? 内联函数:用** inline 修饰的函数叫做内联函数,编译时C编译器会在调用…

PostgreSQL行级安全策略探究

前言 最近和朋友讨论oracle行级安全策略(VPD)时,查看了下官方文档,看起来VPD的原理是针对应用了Oracle行级安全策略的表、视图或同义词发出的 SQL 语句动态添加where子句。通俗理解就是将行级安全策略动态添加为where 条件。那么PG中的行级安全策略是怎…

R包:‘ggcharts好看线图包‘

介绍 ggcharts提供了一个高级{ggplot2}接口,用于创建通用图表。它的目标既简单又雄心勃勃:让您更快地从数据可视化的想法到实际的绘图。所以如何?通过处理大量的数据预处理,为您模糊{ggplot2}细节和绘图样式。生成的图是ggplot对象,可以使用…

CTF php RCE(三)

0x07 日志文件包含 判断类型 使用kali curl -I urlF12 打开F12开发者工具,选中之后F5刷新查看server类型即可 配置文件 直接包含或者访问如果有回显就是, NGINX:NGINX 的配置文件通常位于 /etc/nginx/ 目录下,具体的网站配…

【深度学习入门篇 ④ 】Pytorch实现手写数字识别

【🍊易编橙:一个帮助编程小伙伴少走弯路的终身成长社群🍊】 大家好,我是小森( ﹡ˆoˆ﹡ ) ! 易编橙终身成长社群创始团队嘉宾,橙似锦计划领衔成员、阿里云专家博主、腾讯云内容共创官…

LLMs可以进行任务规划吗?如果不行,LLMs+GNN可以吗?

深度图学习与大模型LLM(小编): 大家好,今天向大家介绍一篇最新发布的研究论文(20240530)。这篇论文探讨了如何通过引入GNN来提高大模型在任务规划(task planning)中的性能。*论文分析了LLMs在任务规划上的局限性,并提出了一种简单而有效的解决方案。* 1.…

VIM模式之间的切换

命令行界面下,常用的文本编辑器是 VI / VIM(VI增强版),VI 是 Linux 最通用的文本编辑器,VIM相较于VI,提供了代码高亮等功能,两者用法完全兼容; 1. 进入 VIM 工作界面 vim 文件名 2. 进入编辑模式 三种方…