单例模式详解

什么是单例模式

首先,单例模式是一种设计模式,按字面意思,指一个类只能创建一个对象,当创建出多个对象的时候,就会出现报错异常

单例模式为何出现?

1.资源共享:某些情况下,多个对象都需要共享一个资源,例如线程池,数据库连接。使用单例模式即可创造出一个公共资源,避免重复资源的重复创造和浪费

2.全局访问:一些对象需要在系统中被频繁访问,如日志,配置信息等。使用单例模式即可提供一个全局访问点,方便其他对象直接获取改实例对象

3.控制实例数量:在某些情况下,系统中运行存在一个实例,如窗口管理,任务管理器等。使用单例模式可以限制实例的数量,确保系统的稳定性和安全性


单例模式下的两种模式

1.饿汉模式
//饿汉模式
class hungrySingleton{//一开始就创建好对象了 (十分迫切地想要创建对象)private static hungrySingleton hungrySingleton = new hungrySingleton();//通过这个方法来获取实例对象public static hungrySingleton getInstance(){return hungrySingleton;}public hungrySingleton(){}
}

是由代码可知,饿汉模式下,十分急于想创建出对象,故一开始就把对象创建好了,通过getInstance方法来获取对象实例


2.懒汉模式
//懒汉模式  只有当调用方法的时候  实例才会被创建
class LazySingleton{//只要当别人调用方法时 才会创建实例对象 不急不慢private static LazySingleton Lazysingleton = null;public static LazySingleton getLazySingleton(){synchronized()if(Lazysingleton == null){//只有第一次获取时才能获取到实例对象Lazysingleton = new LazySingleton();return Lazysingleton;}return Lazysingleton;}public LazySingleton(){}
}

反观懒汉模式,并不是一开始就加载对象,而是当需要时,你就调用方法获得实例,显现出了它的不紧不慢,懒的特点


细节重点:

无论是懒汉模式,还是饿汉模式,我们都能注意到,无论是变量还是方法,都加了static关键字,这其中有什么说法呢?

我们知道,静态资源随着类的加载而加载,且类对象在其进程中,也是只有唯一的一份,这也就意味着类里面的静态资源,也只有独一份的存在,故static在中起到的作用为:

随着类的加载而加载,保证资源只有独一份

同时,我们也可以反过来想,如果这里的属性方法不加关键字,那么资源不就是随着对象的创建而被创建,可以通过实例对象.资源的方法被获取,那资源岂不是取之不尽用之不竭了,与我们的单例两字完全背道而驰

 public static void main(String[] args) {hungrySingleton h = hungrySingleton.getInstance();hungrySingleton h1 = hungrySingleton.getInstance();System.out.println(h == h1);}


线程安全:
原子性

上述的两种模式,其中有一个存在线程安全问题,哪么到底是哪一个呢?

我们分析:

饿汉模式下,资源直接被创建出来,通过方法来获取实例,这区间只存在读操作(获得对象)

在懒汉模式下,刚开始的资源变量被赋值为null,当想获得此实例时,调用方法,但是方法中有一个if的条件判断 if(LazySingleton == null),而这里就涉及到了读操作,如果满足条件,对资源变量赋值,这时候就涉及到了写操作,显然,在既有读也有写的操作中,懒汉模式是线程不安全的!


如何解决:

解决线程安全,首先需要知道它产生线程安全的原因,这里的原因无非是既有读,又有写操作,故操作非原子性,于是我们即可以搬出synchronized进行加锁,使操作原子性

class LazySingleton{//只要当别人调用方法时 才会创建实例对象 不急不慢private static LazySingleton Lazysingleton = null;public static LazySingleton getLazySingleton(){synchronized(LazySingleton.class){if(Lazysingleton == null){//只有第一次获取时才能获取到实例对象Lazysingleton = new LazySingleton();return Lazysingleton;}return Lazysingleton;}}public LazySingleton(){}
}


但此时,又会衍生出一个问题:每次执行getInstance方法获取实例对象,都需要加锁吗?

我们知道,加锁/释放锁都是有开销的,如果此资源被频繁地使用,每次使用都需要执行一次加锁操作,其开销也是巨大的

我们发现,当第一次执行方法后,此后的Lazysingleton便不是null了,于是在其之后调用方法的直接返回实例即可了,故我们只需要对第一次创建对象时加锁就行了,对象创建后就没必要再加锁了

public static LazySingleton getLazySingleton(){if(Lazysingleton == null){synchronized (LazySingleton.class){if(Lazysingleton == null){Lazysingleton =  new LazySingleton();return Lazysingleton;}}}return Lazysingleton;}

内存可见性:

设想,当有大量线程同时通过方法来获取实例对象时,此时实例对象都被读为空,由于编译器优化,可能将已经实例化好的对象依然读成null,此时就会创建出多个实例对象


指令重排序:

什么是指令重排序呢?

比如一个操作的正常指令顺序为1 2 3,当由于编译器的优化(没错,又是它),使指令操作变成1 3 2,而这对于单线程是没什么问题,但对于多线程来说,就会出现问题了

这里我们把load 资源赋值 返回资源操作比喻成指令123

设想,线程1由于指令重排序使操作变成了132

线程1执行完指令13后--->(此时变量还没有被赋值,直接被return了),这时线程2切进来了开始执行,对于线程2来说,既然线程1已经执行了3操作(return Lazysingleton),表明此时的资源为非空了,那么线程2也就直接返回资源了(return Lazysingleton)。但此时的资源并不是完整的,因为线程1的2操作还没有执行呢(Lazysingeton = new LazySingeton),所以此时t2拿到的是非法的对象,故出现问题


解决方法:

volatile

 volatile private static LazySingleton Lazysingleton = null;public static LazySingleton getLazySingleton(){if(Lazysingleton == null){synchronized (LazySingleton.class){if(Lazysingleton == null){Lazysingleton = new LazySingleton();return Lazysingleton;}}}return Lazysingleton;}

故volatile具有两个功能:

1.解决内存可见性

2.解决指令重排序

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

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

相关文章

双向链表也叫双链表

双向链表也叫双链表 双向链表也叫双链表 每个节点都有两个指针,分别指向 直接前驱节点、直接后继节点 双向链表中任意一个节点,都可以通过通过它的前驱节点和后继节点,访问其他节点 节点如下 节点定义 ListNode // 节点的值 T element; /…

康谋技术 | 深入探讨:自动驾驶中的相机标定技术

随着自动驾驶技术的快速发展,多传感器的数据采集和融合可以显著提高系统的冗余度和容错性,进而保证决策的快速性和正确性。在项目开发迭代过程中,传感器标定扮演着至关重要的角色,它位于数据采集平台与感知融合算法之间&#xff0…

【R语言】混合图:小提琴图+箱线图

{ggstatsplot} 是 {ggplot2} 包的扩展,用于创建图形,其中包含信息丰富的绘图本身中包含的统计测试的详细信息。在典型的探索性数据分析工作流程中,数据可视化和统计建模是两个不同的阶段:可视化通知建模,而建模又可以建…

【FreeRTOS】使用CubeMX快速移植FreeRTOS工程到蓝桥杯开发板(STM32G431RBT6)

使用CubeMX快速创建FreeRTOS工程到蓝桥杯开发板(STM32G431RBT6) CubeMX配置CubeMX基础工程的配置☆FreeRTOS相关配置FreeRTOS配置选项卡的解释 软件工程架构与程序设计小综合:任务的创建删除、挂起与恢复设计cubexMX配置创建任务软件程序设计…

工业自动化,3D视觉技术3C薄片自动化上料

随着制造业的快速发展,3C行业对薄片类零件的上料需求日益增长。传统的上料方式往往依赖于人工操作,效率低下且存在误差。为了解决这一问题,3D视觉技术应运而生,为3C薄片自动化上料提供了强大的技术支持。本文将探讨3D视觉技术如何…

HarmonyOS开发实例:【分布式手写板】

介绍 本篇Codelab使用设备管理及分布式键值数据库能力,实现多设备之间手写板应用拉起及同步书写内容的功能。操作流程: 设备连接同一无线网络,安装分布式手写板应用。进入应用,点击允许使用多设备协同,点击主页上查询…

stm32f103c8t6学习笔记(学习B站up江科大自化协)-SPI

SPI通信 SPI,(serial peripheral interface),字面翻译是串行外设接口,是一种通用的数据总线,适用于主控和外挂芯片之间的通信,与IIC应用领域非常相似。 IIC无论是在硬件电路还是在软件时序设计…

Covalent Network(CQT)宣布推出面向 Cronos 生态的捐赠计划与 API 积分,为 Web3 创新赋能

为了促进 Web3 领域的创新,Covalent Network(CQT)宣布将其捐赠计划向 Cronos 生态系统中的开发者拓展。这一战略性举措,旨在通过向 Cronos 网络中基于 Covalent Network(CQT)API 构建的项目提供支持和资源&…

多模态大语言模型综述

节前,我们星球组织了一场算法岗技术&面试讨论会,邀请了一些互联网大厂朋友、参加社招和校招面试的同学,针对算法岗技术趋势、大模型落地项目经验分享、新手如何入门算法岗、该如何准备、面试常考点分享等热门话题进行了深入的讨论。 汇总…

【网络安全 | 密码学】JWT基础知识及攻击方式详析

前言 JWT(Json Web Token)是一种用于在网络应用之间安全地传输信息的开放标准。它通过将用户信息以JSON格式加密并封装在一个token中,然后将该token发送给服务端进行验证,从而实现身份验证和授权。 流程 JWT的加密和解密过程如…

HTML5漫画风格个人介绍源码

源码介绍 HTML5漫画风格个人介绍源码,源码由HTMLCSSJS组成,记事本打开源码文件可以进行内容文字之类的修改,双击html文件可以本地运行效果,也可以上传到服务器里面,重定向这个界面 效果截图 源码下载 HTML5漫画风格…

【honggfuzz学习笔记】honggfuzz的基本特性

本文架构 1.动机2.honggfuzz的基本概念官网描述解读 3. honggfuzz的反馈驱动(Feedback-Driven)软件驱动反馈(software-based coverage-guided fuzzing)代码覆盖率代码覆盖率的计量单位 代码覆盖率的统计方式 硬件驱动反馈( hardware-based co…

MCU最小系统晶振模块设计

单片机的心脏:晶振 晶振模块 单片机有两个心脏,一个是8M的心脏,一个是32.768的心脏 8M的精度较低,所以需要外接一个32.768khz 为什么是8MHZ呢,因为内部自带的 频率越高,精度越高,功耗越大&am…

2024Guitar Pro 8.1 Mac 最新下载、安装、激活、换机图文教程

吉他爱好者必备神器:Guitar Pro v8.1.1 Build 17深度解析 随着数字音乐制作和学习的日益普及,越来越多的吉他爱好者开始寻找能够帮助他们提升技能、创作音乐的专业工具。在众多吉他制作软件中,Guitar Pro因其强大的功能和易用的界面备受推崇…

超平实版Pytorch CNN Conv2d

torch.nn.Conv2d 基本参数 in_channels (int) 输入的通道数量。比如一个2D的图片,由R、G、B三个通道的2D数据叠加。 out_channels (int) 输出的通道数量。 kernel_size (int or tuple) kernel(也就是卷积核,也可…

2024第十五届蓝桥杯JavaB组省赛部分题目

目录 第三题 第四题 第五题 第六题 第七题 第八题 转载请声明出处,谢谢! 填空题暂时可以移步另一篇文章:2024第十五届蓝桥杯 Java B组 填空题-CSDN博客 第三题 第四题 第五题 第六题 第七题 第八题 制作不易,还请点个赞支持…

go语言context

context在服务端编程基本都贯穿所有, Context 是请求的上下文信息。对于RPC Server来说,一般每接收一个新的请求,会产生一个新的Context,在进行内部的函数调用的时候,通过传递Context,可以让不同的函数、协…

pytest学习-pytorch单元测试

pytorch单元测试 一.公共模块[common.py]二.普通算子测试[test_clone.py]三.集合通信测试[test_ccl.py]四.测试命令五.测试报告 希望测试pytorch各种算子、block、网络等在不同硬件平台,不同软件版本下的计算误差、耗时、内存占用等指标. 本文基于torch.testing._internal 一…

春藤实业启动SAP S/4HANA Cloud Public Edition项目,与工博科技携手数字化转型之路

3月11日,广东省春藤实业有限公司(以下简称“春藤实业”)SAP S/4HANA Cloud Public Edition(以下简称“SAP ERP公有云”)项目正式启动。春藤实业董事长陈董、联络协调项目经理慕总、内部推行项目经理陈总以及工博董事长…

【函数式接口使用✈️✈️】通过具体的例子实现函数结合策略模式的使用

目录 前言 一、核心函数式接口 1. Consumer 2. Supplier 3. Function,> 二、场景模拟 1.面向对象设计 2. 策略接口实现(以 Function 接口作为策略) 三、对比 前言 在 Java 8 中引入了Stream API 新特性,这使得函数式编程风格进…