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

单例模式

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

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

单例模式具体的实现⽅式有很多.最常⻅的是"饿汉"和"懒汉"两种
单例模式分为:饿汉模式懒汉模式。单例模式之所以被称为单例模式,是因为我们在创建单例模式类的时候,就把该类的构造方法使用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,一经查实,立即删除!

相关文章

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协…

理解计算着色器中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…

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成功后…

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

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

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

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

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

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

C# OpenVINO Nail Seg 指甲分割 指甲检测

目录 效果 模型信息 项目 代码 数据集 下载 C# OpenVINO Nail Seg 指甲分割 指甲检测 效果 模型信息 Model Properties ------------------------- date:2024-02-29T16:41:28.273760 author:Ultralytics task:segment version&#…

【GitHub】修改默认分支

GitHub的默认分支为main,但我们常常习惯使用master作为默认分支,那在GitHub上如何将master修改为默认分支呢? 全局修改 点击头像,选择菜单栏中的设置 输入master作为默认分支,然后执行updating即可! 单项…

springboot+vue实现oss文件存储

前提oss准备工作 进入阿里云官网:阿里云oss官网 注册 搜OSS,点击“对象存储OSS” 第一次进入需要开通,直接点击立即开通,到右上角AccessKey管理中创建AccessKey,并且记住自己的accessKeyId和accessKeySecret&#…

【Unity】构建简单实用的年份选择器(简单原理示范)

在许多应用程序和游戏中,年份选择是一个常见的需求。无论是在日历应用程序中查看事件,还是在历史类游戏中选择时间段,年份选择器都是用户体验的重要组成部分,下面实现一个简易的年份选择器。 一、效果预览: 目录 一、…

树莓派驱动编译

驱动编译前提:驱动代码的编译需要提前编译号的内核 驱动(3种实现方法,2条路线)_驱动编写三种方法-CSDN博客 驱动的编写_驱动编写-CSDN博客 一、概念 1.1、驱动认识 1、裸机程序中是直接操控硬件的,操作系统…