设计模式———单例模式

单例也就是只能有一个实例,即只创建一个实例对象,不能有多个。

可能会疑惑,那我写代码的时候注意点,只new一次不就得了。理论上是可以的,但在实际中很难实现,因为你无法预料到后面是否会脑抽一下~~因此我们就可以通过编码技巧,让编译器来帮助我们检查约束。

单例模式又分为两种:饿汉式和懒汉式区别在于实例对象创建的时机不同

0x00 饿汉式

说到饿汉,那一定是很饥饿的人,很急切,也就是说这个实例对象创建的时机比较早,在类加载的时候就创建了。

要点

  • 1、由于创建时机较早,设置为静态即可在类加载的时候就可以创建实例对象

  • 2、由于只能创建一个实例对象,因此将构造函数私有化

  • 3、对外提供一个获取实例对象的静态类方法

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

0x01 懒汉式

懒汉,顾名思义,很懒,比较缓慢,也就是说这个实例对象是在使用到的时候才去创建。

要点

  • 1、一开始设置为null,直到在使用的时候再去new实例对象

  • 2、由于只能创建一个实例对象,因此将构造函数私有化

3、对外提供一个获取实例对象的静态类方法

public class SingletonLazy {private static SingletonLazy instance = null;public static SingletonLazy getInstance(){if(instance == null){instance = new SingletonLazy();}return instance;}private SingletonLazy(){}
}

0x02 单例模式与多线程

众所周知,许多在单线程环境下的代码一到多线程环境下就会出错,在此将对单例模式在多线程下的编写进行调整优化~

先来看看饿汉式的代码,我们发现这个实现的方式是在类加载的时候就去实例化对象了,而后续在多线程中掉用getInstance方法来获取实例对象的时候,只会进行返回操作,即”只读”因此多个线程在操作的时候是安全的

再来看看懒汉式,可以发现在调用getInstance方法的时候,会进行修改操作,如果恰巧有两个线程同时进入了if,然后就会进行new操作,那不就创建了多个实例对象了,如果恰巧每个对象不是很轻量,可能有很多属性,加载了几十G的数据到内存中......

因此解决方法是进行加锁操作,保证if和new操作是原子的

public class SingletonLazy {private static SingletonLazy instance = null;public static SingletonLazy getInstance(){synchronized(SingletonLazy.class){if(instance == null){instance = new SingletonLazy();}}return instance;}private SingletonLazy(){}
}

这样修改以后,就能保证if和new操作是一个整体,此时线程的安全问题就得到了改善。

但是这样写是否就真的完了呢?

答案:不是。因为我们是单例模式,所以只需要new一次之后,实例对象就不可能是null了,后续直接return对象就行了。假如我们现在已经创建好了一个对象,当后续有多个线程去调用getInstance方法的时候,需要去获取到这把锁才能进行返回操作,也就是我们的多线程变成了串行化,并发程度几乎没了~

那是否有办法,既可以保证代码线程安全,又不会对执行效率产生大的影响呢?

如下代码:

public class SingletonLazy {private static SingletonLazy instance = null;public static SingletonLazy getInstance(){if(instance == null){synchronized(SingletonLazy.class){if(instance == null){instance = new SingletonLazy();}}}return instance;}private SingletonLazy(){}
}

与前面的代码对比,可以发现,在外层多加了一个if语句。

分析

当有多个线程进入了第一个if语句,此时里面有一个加锁操作,这样可以保证只创建了一个实例对象。假设此时已经创建好了一个实例对象了,当下一次又有多个线程进来时,由于instance不为null,直接返回了,并不会进入到加锁操作,此时并发并没有再受到影响了,既保证了正确又保证了效率。

总结

在锁外面的if语句保证了是否要进行加锁操作,即如果还没有创建实例对象,此时线程由于需要进行修改操作要进行加锁才能保证安全,如果已经创建了实例对象,此时线程安全了就不用加锁了。

在锁里面的if语句是来保证只创建一个实例对象。

0x03 指令重排序

上述代码其实还不够安全,还存在指令重排序的问题。

指令重排序,本质是编译器为了提高执行效率,调整原有的代码执行顺序(前提是保持逻辑不变)。

接下来具体问题具体分析:

上述的代码中,出现了一个new操作,而new操作其实是分三步的,第一步,申请内存空间,第二步,在内存空间上构造对象,第三步,把内存地址赋值给对象引用。一般是按照1,2,3的顺序执行的,但是编译器优化过后,可能会按照1,3,2的顺序执行,在单线程环境下都可以,但是在多线程环境下则不是。如果线程1是按照1,3,2顺序执行完了3后,线程2此时返回了这个实例对象,但是此时这个对象还没有初始化呢,也就是说这是个非法对象,当我们的线程2去访问这个对象的属性或方法时,此时就是非法,会出错。此时我们还需要再对instance加一个限制操作,即用volatile来修饰instance。

最终代码

public class SingletonLazy {private static volatile SingletonLazy instance = null;public static SingletonLazy getInstance(){if(instance == null){synchronized(SingletonLazy.class){if(instance == null){instance = new SingletonLazy();}}}return instance;}private SingletonLazy(){}
}

至此,这段“健壮”的代码基本可以满足使用了~

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

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

相关文章

【记录】Python|Selenium 下载 PDF 不预览不弹窗(2024年)

版本: Chrome 124Python 12Selenium 4.19.0 版本与我有差异不要紧,只要别差异太大比如 Chrome 用 57 之前的版本了,就可以看本文。 如果你从前完全没使用过、没安装过Selenium,可以参考这篇博客《【记录】Python3|Sele…

大型网站系统架构演化实例_1.单体架构和垂直架构

大型网站的技术挑战主要来自于庞大的用户,高并发的访问和海量的数据,任何简单的业务一旦需要处理数以P计的数据和面对数以亿计的用户,问题就会变得很棘手。通常大型网站架构主要解决这类问题。 1.第一阶段:单体架构 大型网站都是…

安防视频监控/视频集中存储EasyCVR平台级联时,下级平台未发流是什么原因?

安防视频监控/视频集中存储/云存储/磁盘阵列EasyCVR平台可拓展性强、视频能力灵活、部署轻快,可支持的主流标准协议有国标GB28181、RTSP/Onvif、RTMP等,以及支持厂家私有协议与SDK接入,包括海康Ehome、海大宇等设备的SDK等。平台既具备传统安…

Go 单元测试之Mysql数据库集成测试

文章目录 一、 sqlmock介绍二、安装三、基本用法四、一个小案例五、Gorm 初始化注意点 一、 sqlmock介绍 sqlmock 是一个用于测试数据库交互的 Go 模拟库。它可以模拟 SQL 查询、插入、更新等操作,并且可以验证 SQL 语句的执行情况,非常适合用于单元测试…

如何安装MacOS的虚拟机?mac安装虚拟机的步骤 虚拟机安装MacOS VMware Fusion和Parallels Desktop19

要在Mac上运行MacOS的虚拟机,常用的方法是使用虚拟化软件如VMware Fusion或Parallels Desktop。 以下是安装MacOS的虚拟机的主要步骤: 1. 检查系统要求:确定您的Mac硬件和操作系统满足安装要求。您需要一台具备足够性能的Mac,并…

【前端Vue】Vue从0基础完整教程第7篇:组件化开发,组件通信【附代码文档】

Vue从0基础到大神学习完整教程完整教程(附代码资料)主要内容讲述:vue基本概念,vue-cli的使用,vue的插值表达式,{{ gaga }},{{ if (obj.age > 18 ) { } }},vue指令,综合…

GPT国内怎么用?4月最新版本来了

ChatGPT镜像 今天在知乎看到一个问题:“平民不参与内测的话没有账号还有机会使用ChatGPT吗?” 从去年GPT大火到现在,关于GPT的消息铺天盖地,真要有心想要去用,途径很多,别的不说,国内GPT的镜像…

37、Tomato(VulnHub)

Tomato 一、nmap 2211是ssh的端口,21的ftp也不是弱密码 二、web渗透 随便看看 目录爆破 /seclists/Discovery/Web-Content/common.txt /antibot_image/antibots/readme.txt 发现该站点存在反爬机制 /antibot_image/antibots/info.php 提示我们该网页存在个参数 GET&…

FineBI 6.0 Linux 部署、ClickHouse 源配置

文章目录 FineBI 概述FineBI 部署安装环境说明1.下载安装包2.安装3.初始化设置4.登录5.快速入门 启动与关闭启动关闭 ClickHouse 源配置开启驱动上传功能驱动上传数据库连接配置基础表属性设置数据导入 FineBI 概述 FineBI 是一款国产的商业智能(BI)软件…

Quartz + SpringBoot 实现分布式定时任务

文章目录 前言一、分布式定时任务解决方案二、Quartz是什么?1.quartz简介2.quartz的优缺点 二、Quartz分布式部署总结 前言 因为应用升级,由之前的单节点微服务应用升级为集群微服务应用,所以之前的定时任务Spring Scheduled不再适用了&…

固定测斜仪:工程观测的精密利器

在工程观测测量领域,固定测斜仪扮演着至关重要的角色。固定测斜仪,凭借其耐冲击型倾斜传感器、出色的可靠性、快速稳定的特点,以及简洁的安装和智能识别功能,已成为行业内重要工具。其输出信号为RS485数字量,可直接显示…

Postman之全局变量与环境变量配置

实际开发中可能需要不停切换环境,接口中来回输入环境地址比较麻烦,故而通过定义变量来节约频繁更换测试地址所耗费的时间。Postman 允许定义自己的全局变量(Globals)与环境变量(Environment),最…

51-41 Stable Video Diffusion,高质量视频生成新时代

23年11月,Stability AI公司公开了稳定视频扩散模型Stable Video Diffusion(SVD)的代码和权重,视频生成迎来了新时代。SVD是一种潜在扩散模型,支持文本生成视频、图像生成视频以及物体多视角3D合成。从工程角度来看,本文主要提出了…

如何使用Postgres的扩展(如PostGIS)来支持地理空间数据

文章目录 解决方案1. 安装PostGIS扩展2. 创建地理空间数据表3. 插入地理空间数据4. 进行地理空间查询 示例代码 在PostgreSQL中,我们可以使用扩展来增强数据库的功能。对于地理空间数据,PostGIS是一个特别有用的扩展,它提供了对地理对象&…

Linux安装mysql 8.0

1.使用root登录服务器 2.创建安装包存放目录 # mkdir /software # cd /software3.下载并解压mysql安装包 # wget https://dev.mysql.com/get/Downloads/MySQL-8.0/mysql-8.0.21-linux-glibc2.12-x86_64.tar.xz # tar xvJf mysql-8.0.21-linux-glibc2.12-x86_64.tar.xz # mv m…

反激电源——TL431及光耦反馈电路计算(不涉及环路补偿)

一、TL431及光耦反馈电路 TL431以及光耦电路是反激的副边反馈类型电路中的常见应用。 其反馈工作原理为:当副边的输出电压升高时,TL431的REF点采样电压也会升高,使得TL431的导通量增加,同时光耦内部的发光二极管流过的电流也增大&…

利用动态规划优化10年投资回报:策略、证明与算法分析

利用动态规划优化10年投资回报:策略、证明与算法分析 a. 存在最优投资策略的证明b. 最优子结构性质的证明c. 最优投资策略规划算法设计d. 新限制条款下最优子结构性质的证明 在面对投资策略规划问题时,我们的目标是在10年后获得最大的回报。Amalgamated投…

产废端实时音视频监控系统在运输车辆驾驶室中的应用

实时音视频监控系统可通过在运输车辆驾驶室安装音视频摄录设备,实现将运输车辆内部及周围环境音视频数据通过移动网络实时回传指挥中心的功能。 前端摄录设备主要负责采集车内外的视音频信息,为了保障车辆及运输人员 的安全,应合理选择摄录设…

HTML5 <video> 标签属性、API 方法、事件、自定义样式详解与实用示例

HTML5 <video> 标签为网页内嵌视频提供了强大且便捷的功能。以下是对 <video> 标签的主要属性、API 方法、事件、自定义样式及其使用示例的详细介绍&#xff1a; 一、属性 1. src 定义&#xff1a;指定视频文件的 URL。示例&#xff1a;<video src"my_v…

linux-centos虚拟机设置固定ip

环境准备 虚拟机版本&#xff1a;centos7 安装环境&#xff1a;vmware17 1、设置网络连接 虚拟机-设置-网络适配器-NAT模式 2、查看子网信息 编辑-虚拟网络编辑器-NAT模式-NAT设置 查看子网ip和网关ip 下一步要用 3、修改配置文件 vim /etc/sysconfig/network-scripts…