实现一个线程安全的单例模式

单例模式

单例模式能保证某个类在程序中只存在唯⼀⼀份实例,⽽不会创建出多个实例

某个类,在一个类,只应该创建出一个实例,使用单例模式,就可以对咱们的代码进行一个更严格的校验和检查

单例模式具体的实现⽅式有很多.最常⻅的是"饿汉"和"懒汉"两种
单例模式分为:饿汉模式懒汉模式。单例模式之所以被称为单例模式,是因为我们在创建单例模式类的时候,就把该类的构造方法使用private进行修饰,以便在该类外,不能直接创建出一个实例。

饿汉模式

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

对于饿汉模式来说,getInstance直接返回Instance实例,这个操作本质就是"读操作"

多个线程读同一个变量,是线程安全的!!

懒汉模式

实质是在该模式中不着急初始化出实例,在类外需要的时候,在进行初始化

class SingletonLazy{private volatile static SingletonLazy instance = null;public static SingletonLazy getInstance() if(instance == null ){instance = new SingletonLazy();}return instance;}public SingletonLazy() {}
}
public class ThreadDemo10 {public static void main(String[] args) {SingletonLazy s1 = SingletonLazy.getInstance();}}

 

针对上述问题,如何解决,是需要把if和new 两个操作,打包成一个原子的

代码修改如下

class SingletonLazy{private static Object locker = new Object();public  static  SingletonLazy getInstance() {synchronized (locker) {if(instance == null ){instance = new SingletonLazy();}}return instance;}public SingletonLazy() {}
}
public class ThreadDemo10 {public static void main(String[] args) {SingletonLazy s1 = SingletonLazy.getInstance();SingletonLazy s2 = SingletonLazy.getInstance();System.out.println(s1 == s2);}}

但是加了锁 ,又出现了新的问题

如果instance 已经创建过了  此后后续在调用getInstance 就直接返回instance实例了吧,此时,针对已经没有线程安全问题的代码,仍然是每次调用都先加锁在解锁,效率非常低了.

加锁意味着可能会产生阻塞,一旦线程阻塞,啥时候能解除,就不知道了

解决问题:在加锁外头套层if 判定一下这个代码是否需要加锁 ,如果需要加锁,才加,不需要加锁,那就算了

这时候 代码仍有点问题

指令重排序:也是编译器优化的一种方式

                    调整原有代码的执行顺序,保证逻辑不变的前提下,提高程序的效率

上述代码中,由于t1线程执行完1 3 之后 调度走,此时instance 指向的是一个非null的 但是未初始化的对象,此时t2线程判定instance == null 不成立 就会直接return  如果t2继续使用instance里面的属性和方法,就会出现问题(此时这里的属性 都是未初始化的"全0 "值) 就会引起代码逻辑上出现问题

解决上述问题 核心思路 还是volatile

volatile有两个功能

1.保证内存可见性:每次访问变量必须都要重新读取内存,而不会优化到寄存器/缓存中

2.禁止指令重排序.真对这个被volatile修饰的变量的读写操作相关指令,是不能被重新排序的

class SingletonLazy{private volatile static SingletonLazy instance = null;private static Object locker = new Object();public  static  SingletonLazy getInstance() {if(instance == null) {synchronized (locker) {if(instance == null ){instance = new SingletonLazy();}}}return instance;}public SingletonLazy() {}
}
public class ThreadDemo10 {public static void main(String[] args) {SingletonLazy s1 = SingletonLazy.getInstance();SingletonLazy s2 = SingletonLazy.getInstance();System.out.println(s1 == s2);}}

总结一下 线程安全的单例模式 ---懒汉模式

1.在正确位置加锁

2.双重if 判定

3.使用volatile关键字

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

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

相关文章

Linux之定时任务01

简介 Linux定时任务是一种可执行的命令或者脚本,在特定的时间或者时间间隔下自动执行。通过在系统中预设一些需要执行的任务,可以让Linux定时任务自动执行并完成这些任务。定时任务可以用于自动备份、系统清理、监控、自动化维护等任务。 一、apache服务器监控 [rootlocalhost…

代码随想录算法训练营day27

题目:93.复原IP地址、78.子集、90.子集II 参考链接:代码随想录 93.复原IP地址 思路:本题的思路和上题切割回文串类似,也是先要写一个判断函数,然后一个个切割。对返回条件,如果路径长度已经为4&#xff…

DevEco Studio下载与安装(Windows)

下载地址: HUAWEI DevEco Studio和SDK下载和升级 | HarmonyOS开发者 安装时直接点击 next 即可。 运⾏已安装的DevEco Studio,⾸次使⽤,请选择Do not import settings,单击OK。 1.安装Node.js 如果本地有下载,可以…

前端JS 时间复杂度和空间复杂度

时间复杂度 BigO 算法的时间复杂度通常用大 O 符号表述,定义为 T(n) O(f(n)) 实际就是计算当一个一个问题量级(n)增加的时候,时间T增加的一个趋势 T(n):时间的复杂度,也就相当于所消耗的时长 O&#xff1…

乐吾乐Web可视化RTSP播放

背景 乐吾乐致力于物联网和智能制造等场景的Web可视化平台和解决方案,其中摄像头播放必不可少。 当前国内摄像头都以RTSP协议为主,而HTML不能直接读取RTSP协议,因此需要一个转流服务。乐吾乐Web可视化播放RTSP也是如此: RTSP协…

ArcGIS专用语言:Arcade详细介绍(一)

Arcade语言是专为在ArcGIS中使用而设计的。是一种可移植、轻量级且安全的表达语言,用于在ArcGIS应用程序中创建自定义内容。 与其他表达式语言一样,它可以执行数学计算、设置文本格式和计算逻辑语句,还支持多语句表达式、变量和流控制语句。…

理解计算着色器中glsl语言的内置变量

概要 本文通过示例的方式,着重解释以下几个内置变量: gl_WorkGroupSizegl_NumWorkGroupsgl_LocalInvocationIDgl_WorkGroupIDgl_GlobalInvocationID 基本概念 局部工作组与工作项 一个3x2x1的局部工作组示例如下,每个小篮格子表示一个工作项…

Vulnhub靶机:basic_pentesting_1

一、介绍 运行环境:Virtualbox 攻击机:kali(10.0.2.4) 靶机:basic_pentesting_1(10.0.2.6) 目标:获取靶机root权限和flag 靶机下载地址:https://www.vulnhub.com/en…

密码学——基本概念

引言 在计算机和通信技术发达的现代社会,密码已经成为防止信息被篡改,盗取等方面不可或缺的技术。可应用于:本人身份认证,网上交易加密和认证。保证文件不被篡改的电子签名。电子邮件的加密等等领域。 密码学术语: 密码 cipher 基本词汇: 明文P(Plain text)= 没有经…

TCP缓存

TCP缓存是指TCP协议在数据传输过程中使用的一种机制,用于临时存储和管理数据包。它主要有三个作用:提高网络性能、保证数据的可靠性和实现流量控制。 首先,TCP缓存可以提高网络性能。当发送端发送数据时,TCP协议会将数据分割成若…

如何实现无公网ip远程访问本地安卓Termux部署的MySQL数据库【内网穿透】

文章目录 前言1.安装MariaDB2.安装cpolar内网穿透工具3. 创建安全隧道映射mysql4. 公网远程连接5. 固定远程连接地址 前言 Android作为移动设备,尽管最初并非设计为服务器,但是随着技术的进步我们可以将Android配置为生产力工具,变成一个随身…

VR危险环境模拟介绍|VR虚拟现实设备

VR危险环境模拟是指利用虚拟现实技术来模拟和展现各种危险环境,以便训练人员应对紧急情况、提高安全意识和应急反应能力。这种模拟可以涉及到工业、医疗、紧急救援等多个领域,旨在帮助人们在真实环境中面对危险时能够做出正确的应对和决策。 VR危险环境…

Linux alias命令(为复杂命令创建别名,其中命令可带选项或参数)

文章目录 Mastering the Linux alias Command(精通Linux的alias命令)1. Understanding the alias Command(理解alias命令)示例Ubuntu20.04 arm操作系统OpenEuler20.03 arm操作系统 2. Basic Usage of alias(alias的基本…

AMEYA360:广和通5G智能模组SC171支持Android、Linux和Windows系统,拓宽智能物联网应用

世界移动通信大会2024期间,广和通宣布:5G智能模组SC171除支持Android操作系统外,还兼容Linux和Windows系统,帮助更多智能终端客户快速迭代产品,拓宽智能化应用覆盖范围。 广和通SC171系列基于高通QCM6490物联网解决方案…

基于Python3的数据结构与算法 - 07 归并排序

一、归并 引入 假设现在的列表分两段有序,如何将其合并成为一个有序列表。 这种操作成为一次归并。 归并的思路 分别对两个列表进行遍历,比较两个列表中的最小值,将更小的取出来。取出后一次进行上操作,直到其中一个列表中的元…

springboot+vue实现Minio文件存储

安装minio 首先点击进入MINIO官网,进行一个minio服务器的下载 下载好了之后在本地磁盘找一个文件夹,把下载的exe放入文件夹,再新建一个文件夹准备存放数据和文件 在当前目录cmd进入控制台,输入代码 minio.exe server data成功后…

内衣洗衣机什么牌子好又便宜?实力非凡机型深度测评

内衣裤这种小件的衣物紧密接触皮肤,更是接触特殊生理部位,所以,内衣裤对卫生标准有着特殊要求,现在很多人都是,把内衣裤放到家里的大型洗衣机和其他衣物混洗,你应该知道大型洗衣机由于长期清洗一些大件的衣…

【Linux】——期末复习题(十一)

🎃个人专栏: 🐬 算法设计与分析:算法设计与分析_IT闫的博客-CSDN博客 🐳Java基础:Java基础_IT闫的博客-CSDN博客 🐋c语言:c语言_IT闫的博客-CSDN博客 🐟MySQL&#xff1a…

MySQL 8.0.35 企业版比社区版性能高出 25%?

前言 说实话,比较一下这两个 MySQL 发行版,并不会让我很兴奋。这是因为在我关于 MySQL 的记忆中,如果是谈代码库时,两个发行版之间没有真正的区别。 据我所知,企业版的差异在于附加的插件/组件,因此除非您…

简单版 git快速上手使用 clone项目 新建/切换分支 提交修改

Git是一个广泛使用的版本控制系统,允许多个用户跟踪文件的更改,并协作开发项目。 首先确定自己电脑已经安装了git,具体安装步骤请查找教程,应该不难。 以windows电脑为例,安装完后在搜索栏搜索git会出现 先解释一下这…