【JavaEE】单例模式

作者主页:paper jie_博客

本文作者:大家好,我是paper jie,感谢你阅读本文,欢迎一建三连哦。

本文于《JavaEE》专栏,本专栏是针对于大学生,编程小白精心打造的。笔者用重金(时间和精力)打造,将MySQL基础知识一网打尽,希望可以帮到读者们哦。

其他专栏:《MySQL》《C语言》《javaSE》《数据结构》等

内容分享:本期将会分享设计模式中的单例模式

目录

什么是设计模式

什么是单例模式

单例模式的实现方式

饿汉模式

具体代码

代码分解 

懒汉模式

懒汉模式 - 单线程

具体代码

代码分析

懒汉模式 - 多线程

问题一: 原子性

改进

问题二: 加锁带来的开销

改进

问题三: 指令重排序

改进:


什么是设计模式

设计模式是咱们程序猿圈子中的一些大佬写出来的,为了规范我们的代码,让我们的代码不至于写的见不得人,可以说使用设计模式就等于给了你一个下限,只要你按照这个模式来写,再怎么样也不至于水到哪去. 就可以把它理解为好比棋谱一般.给了我们一些套路,在遇到什么情况,该什么应对. 我们软件开发中就是有许多常见的问题场景,针对这些问题场景,大佬们就总结出来一些固定的套路给我们这些小萌新使用.

什么是单例模式

单例模式它就是能保证某个类只能创建一个实例,而不能创建多个实例.这一点在很多场景中都需要使用.因为往往这类实例需要的内存空间和开销都比较大,我们就需要限制住创建实例的个数.

单例模式的实现方式

单例模式有许多种实现的方式,不过其中最常见的就是饿汉模式和懒汉模式.

饿汉模式

饿汉模式,顾名思义,对于创建这个实例非常迫切,在类一加载就创建好了.

具体代码

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

    }
}

代码分解 

1. 这里的instance是静态属性,类属性. 是随着类的加载而创建.因为一个类只有一个类对象,类属性也只有一份,所以这里只能创建一次实例.

2. 在类外需要获取这个实例需要使用getinstance方法来获取,而不是自己再new一个.

3. 这里在类外再new一个对象会发现编译报错,这是因为这里将它的构造方法设置为私有的,在类外是访问不到.这就保证了只能创建一份实例.

懒汉模式

这里懒汉模式有两种,一种单线程,一种多线程.

懒汉模式 - 单线程

具体代码
class Singleton2 {
    private static Singleton2 instance = null;
    public Singleton2 getInstance() {
        if(instance == null) {
            return new Singleton2();
        }
        return instance;
    }
    
    private Singleton2() {
        
    }
}
代码分析

这里不会在类加载的时候直接创建实例,而是将创建实例放到了方法中. 当第一个调用getinstance方法时就会创建出实例.后面再使用这个方法时因为instance不是null后就不会再创建了.

这样的代码也可以保证只创建一次实例. 创建实例的实例就看代码中什么时候使用这个方法.这样创建实例就不是很急迫,只有需要的时候才会创建,所以叫懒汉. 且这样有一个好处就是如果用不到这个实例它就不会创建,遮掩就省了一笔开销.要知道一般单例模式中的实例都需要占很大的内存空间的,加载的时间需要很久,这样子加载的时间省了,空间也省了.

懒汉模式 - 多线程

在上述的单线程中,是没有多线程安全问题的,但是当在多线程协调工作时就会线程不安全.像饿汉模式也是线程安全的,因为它只涉及到读操作,但是懒汉模式涉及到读和写操作.这样就会有线程安全问题.

问题一: 原子性

我们假设有两个线程,t1和t2.它们都需要使用getinstance这样方法. 这里可能就会有一种情况: t1先执行,到t1执行到if()语句判断后它就被调度走了,这时t2调度过来执行.等t2执行完到new一个实例返回后,t1再执行.但是t1执行的时候它还是认为instance是null,于是它就又创建了一个实例.

这里就是因为这些操作没有具有原子性(当然这里是伪原子,只是针对t2这个线程来说)

改进

我们这里就需要用到我们的加锁操作了.将相关代码加锁!

class Singleton1 {
    private static Singleton1 instance = null;
    public Singleton1 getInstance() {
        synchronized (Singleton1.class) {
            if (instance == null) {
                return new Singleton1();
            }
            return instance;
        }
        
    }
    private Singleton1() {
    }
}
问题二: 加锁带来的开销

这里看似处理了问题,但是还有其他的毛病.这里我们发现加锁操作其实只有第一次创建对象(也就是改操作)是需要的,后面的操作都不需要,但是我们还是需要进行锁竞争,这里就是导致开销比较大.

改进

这里我们在外头再加上一层if判断即可. 这里的第一个if就是判断需不需要加锁,第二个if就是在加锁操作下判断有没有创建实例.

class Singleton1 {
    private static Singleton1 instance = null;
    public Singleton1 getInstance() {
        if(instance == null) {
            synchronized (Singleton1.class) {
                if(instance == null) {
                    return new Singleton1();
                }
            }
        }
        return instance;
    }
    private Singleton1() {
    }
}
问题三: 指令重排序

对于new这个代码,有三个操作: 1. 申请一块内存. 2. 在这块内存中调用构造方法来初始化这个实例. 3. 将这个内存地址赋值到instance中.  这里一般来说我们就是按顺序执行.但是JVM中可能就会给你优化,也就是指令重排序. 可能就会出现 1 3 2这种顺序. 这里就会发生问题: 

这里也假设有t1和t2, 当t1一直执行到new操作的3后,这时就被CPU调度走了,让t2进来执行代码.当t2执行到第一个if判断时,发现instance不为null,他就直接返回了.但是这里的instance是一块没有被初始化的空间地址,这就会导致t2接下来的逻辑发生问题.

改进:

这里我们就需要用到我们的volatile.它有两个作用:

1. 保证内存可见性. 它可以强制让JVM不进行代码优化,保证每次都到内存中读取变量.

2. 禁止指令重排序. 针对volatile修饰的这个变量的相关指令,JVM是不可以优化重排序的.

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

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

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

相关文章

爬虫概念、基本使用及一个类型和六个方法(一)

目录 一、爬虫简介 1.什么是爬虫 2.爬虫的核心 3.爬虫的用途 4.爬虫的分类 5.反爬手段 二、Urllib基本使用 1.导入我们需要的包 2.定义一个url 3.模拟浏览器向服务器发送请求 4.获取响应中的页面的源码 5.打印数据 三、一个类型和六个方法 1.定义url,并…

C++初阶 | [七] string类(上)

摘要:标准库中的string类的常用函数 C语言中,字符串是以\0结尾的一些字符的集合,为了操作方便,C标准库中提供了一些str系列的库函数, 但是这些库函数与字符串是分离开的,不太符合OOP(面向对象)的思想&#…

【vue】vue-slick-carousel插件,实现横向滚动列表手动左右滚动(也可设置为自动滚动)

需求:图片列表横向滚动的时候,隐藏原始滚动条,通过左右箭头控制滚动条往左右按一定的步长移动。 el-carousel走马灯一滚动就是一屏,不适合我的需求 在npm官网搜vue-slick-carousel,查看更详细的配置 vue-slick-caro…

解决xshell连接诶树莓派中文乱码的问题

系统版本 解决办法 在根目录下找到 /etc/profile 修改profile文件,添加以下两行.以便重启之后也能生效: export LANGzh_CN.utf8 export LC_ALLzh_CN.utf8注意: /etc/profile的修改需要root权限才能修改! 在xshell的编码格式改为UTF-8

全志T527设置gpio口输出高电平实际输出低电平

前言 在调试T527的时候,主板另外添加了gpio口去控制usb口的电源开关,软件上面需要在内核运行的时候将gpio口设置输出高电平,usb口才可以正常使用。改好系统固件后,升级发现,机器开机动画过程中可以控制gpio口去打开us…

竞赛选题YOLOv7 目标检测网络解读

文章目录 0 前言1 yolov7的整体结构2 关键点 - backbone关键点 - head3 训练4 使用效果5 最后 0 前言 世界变化太快,YOLOv6还没用熟YOLOv7就来了,如果有同学的毕设项目想用上最新的技术,不妨看看学长的这篇文章,学长带大家简单的…

[C国演义] 第二十三章

第二十三章 两个字符串的最小ASCLL删除和最长重复子数组 两个字符串的最小ASCLL删除和 力扣链接 求 删除字符的ASCLL和的最小值 ⇒ 正难则反 ⇒ 求公共子序列的ASCLL和的最大值 两个数组的dp问题 ⇒ 分区间讨论 ⇒ dp[i][j] -- nums1数组的[0, i] 区间 和 nums2数组的[0, j] …

《opencv实用探索·九》中值滤波简单理解

1、引言 均值滤波、方框滤波、高斯滤波,都是线性滤波方式。由于线性滤波的结果是所有像素值的线性组合,因此含有噪声的像素也会被考虑进去,噪声不会被消除,而是以更柔和的方式存在。这时使用非线性滤波效果可能会更好。中值滤波是…

手搓图片滑动验证码_JavaScript进阶

手搓图片滑动验证码 背景代码效果图展示网站 背景 在做前端项目开发的时候,少不了登录注册部分,既然有登录注册就少不了机器人验证,验证的方法有很多种,比如短信验证码、邮箱验证码、图片滑动、图片验证码等。 由于鄙人在开发中…

“团团活力圈”—“玩转柔力球 青春展风采”青少年柔力球体验活动

柔力球项目是中华优秀传统文化创造性转化、创新性发展的成功典范,它融合了传统太极运动方式与现代竞技双重特征于一体,强调内外双修,是一项集健身性、竞技性、表演性为一体的极富中华民族特色的体育运动。 为进一步促进柔力球运动在青少年人…

RK3588 Yolov5 部署进行目标识别

一、环境说明: 1、上位机 主机配置:win10(强制要求win 10)OS专业版 22H2 虚拟化软件:VMware pro 17.0.2; 虚拟机系统:Ubuntu20.04.1(要求>18.0);x86-64位…

【软考S01计算机系统知识】E01 中央处理单元

E01 中央处理单元 计算机系统硬件基本组成中央处理单元组成功能 多核 CPU 计算机系统硬件基本组成 计算机系统由硬件和软件组成,基本硬件系统由 运算器、控制器、存储器、输入设备 和 输出设备 5大部件组成; 中央处理单元: 运算器、控制器等…

低代码简化开发流程,强大的开发利器

目录 一、与传统IT开发相比,低代码开发的优势 二、低代码是时代发展的产物 三、善用低代码 四、总结 软件开发已经成为企业发展不可或缺的一环。然而,传统的软件开发模式常常面临着繁琐冗长的工作流程、高昂的开发成本以及难以跟进快速变化的市场需求的挑…

微服务调用组件Feign

JAVA 项目中如何实现接口调用? 1)Httpclient HttpClient 是 Apache Jakarta Common 下的子项目,用来提供高效的、最新的、功能丰富 的支持 Http 协议的客户端编程工具包,并且它支持 HTTP 协议最新版本和建议。HttpClient 相比传…

Spring Boot 3 整合 Spring Cache 与 Redis 缓存实战

🚀 作者主页: 有来技术 🔥 开源项目: youlai-mall 🍃 vue3-element-admin 🍃 youlai-boot 🌺 仓库主页: Gitee 💫 Github 💫 GitCode 💖 欢迎点赞…

服务器托管与服务器租用的详细比较

​  在当今数字化时代,服务器托管和服务器租用成为了许多企业和个人选择的两种常见方式。它们都提供了一种将服务器放置在专业机房中的解决方案,但在具体实施和使用过程中存在一些差异。下面将详细比较这两种方式的优势和劣势。 1. 服务器托管 服务器托…

Wnmp本地搭建结合内网穿透实现远程访问本地Wnmp服务

文章目录 前言1.Wnmp下载安装2.Wnmp设置3.安装cpolar内网穿透3.1 注册账号3.2 下载cpolar客户端3.3 登录cpolar web ui管理界面3.4 创建公网地址 4.固定公网地址访问 正文开始前给大家推荐个网站,前些天发现了一个巨牛的 人工智能学习网站, 通俗易懂&a…

拒绝废话,直接开画!Python零基础教程之画图

引文 很多教程,开始教python,就是语法呀,字符类型这些基础的,虽说是基础,你也不能说没用。 但是,对于前期要快速成长的我们来说,属实不够看。 我们是新手,我们是菜鸟,但…

2、Linux_远程操作

远程操作 1.配置ifconfig 1.1输入 ifconfig 查看 ip 的命令( ifconfig ) 1.2搜索 ifconfig 命令(yum search ifconfig) 1.3配置网卡 进入如下目录配置网卡 cd /etc/syscofig/network-scripts编辑 ifcfg-ens33 vi ifcfg-ens33按 i 键进入编辑模式 按 …

好大夫数据爬取

好大夫数据爬取 问诊数据评论数据医生数据科普号数据医患交流数据 可按照疾病进行所有医生的数据,也可以抓所有问诊数据、评论数据 突破限制,快速交付