多线程---单例模式
文章目录
- 什么是单例模式?
- 饿汉模式
- 懒汉模式
- 版本一:最简单的懒汉模式
- 版本二:考虑懒汉模式存在的线程安全问题
- 版本三:更完善的解决线程安全问题
- 版本四:解决指令重排序问题
什么是单例模式?
单例模式:是一种常见的设计模式。即:一些大佬针对一些常见的需求场景,整理出来的一些解决方案。我们只需要套用模式就可以解决问题,极大的便利了我们的开发。
具体来说,单例模式就要求某个类只能有一个实例。
那在Java中怎么实现呢?
我们就会想到“static”这个关键字,static修饰的成员/属性就会变成类成员/属性。当属性变成类属性的时候其实就已经是“单例”的了。因为,JVM在加载类的时候只加载一次,这个类是“单例”的,那么它包含的属性更是“单例”的。
借助static实现“单例模式”有两种模式:饿汉模式和懒汉模式
饿汉模式
//饿汉模式 在类加载阶段就创建了实例 实例创建的时机非常早 非常急迫
class Singleton{// static 修饰的变量是类对象的成员变量 JVM加载时只加载一次private static Singleton instance = new Singleton();public static Singleton getSingleton() {return instance;}// 设置私有的构造方法 防止有人不通过getSingleton方法来获取到我们规定的单个示例 而是在别的类中new Singleton来创建实例private Singleton(){}
}
注:
- Singleton类的构造方法应该设置为私有的,防止别人不使用我们已经创建好的实例再创建新的实例。
- instance应该被private static修饰,构造方法被设置为私有的后,只有通过一个公共的static方法才能获取到实例
- 在类加载的时候就创建了实例,创建实例的时机非常紧迫,所以叫“饿汉模式”
懒汉模式
版本一:最简单的懒汉模式
//懒汉模式:在需要使用到实例的时候再创建实例,创建实例的时机不紧迫
class SingletonLazy{private static SingletonLazy instance = null;public static SingletonLazy getInstance(){if (instance == null){instance = new SingletonLazy();}return instance;}private SingletonLazy(){}
}
注:
- 在首次调用到getInstance的时候才会创建实例,后续再调用到getInstance的时候直接返回已经创建好的实例。
- 饿汉模式的效率更高。原因一:如果后续没人需要使用到实例,则创建实例的过程就被节省下来了;原因二:在类加载的过程中,JVM需要做的工作非常多。把创建实例的过程延后,可以给JVM减轻点负担。
版本二:考虑懒汉模式存在的线程安全问题
在饿汉模式中,调用到getInstance方法只涉及到读操作,不会有线程安全问题。
在懒汉模式中,调用到getInstance方法会进行判断后再创建实例,既涉及到读又涉及到修改。在多线程环境下就有可能创建多个实例,违背了单例模式
// 线程安全的懒汉模式
class SingletonLazy{private static SingletonLazy instance = null;public static SingletonLazy getInstance(){//加锁 保证线程安全 只能创建单个实例synchronized (SingletonLazy.class) {if (instance == null) {instance = new SingletonLazy();}}return instance;}private SingletonLazy(){}
}
版本三:更完善的解决线程安全问题
像上面那样直接加锁,我们虽然可以保证线程是安全的。但是有一个新的问题:懒汉模式只有在第一次创建实例的时候才有线程安全问题,后续使用实例的时候直接返回实例就行,不需要加锁判断。但是像上面那样,在线程安全时也会加锁,降低了代码执行效率。
// 懒汉模式更加完善的解决线程安全问题
class SingletonLazy{private static SingletonLazy instance = null;public static SingletonLazy getInstance(){//判断是否需要加锁if (instance == null) {synchronized (SingletonLazy.class) {// 判断是否已经创建实例//这个if不可少 当线程1 2 同时调用getInstance方法时 线程1执行完会创建实例// 如果没有if 线程2来了不知道是否已经有实例了 还会继续创建实例if (instance == null) {instance = new SingletonLazy();}}}return instance;}private SingletonLazy(){}
}
注:两个if都必不可少,各自有各自的作用:第一个if:在已经创建实例后,判断释放需要继续加锁;第二个if:在没有创建实例时,防止创建多个实例。
版本四:解决指令重排序问题
一个新的问题:
new操作分为三步(粗略): 1.申请内存 2. 初始化实例 3. 将内存首地址赋值给instance
编译器可能进行指令重排序的优化 ,比如:
线程1 将1-2-3 的执行顺序 改为 1-3-2 并且在执行完1-3后 线程2调用getInstance 。线程2看到instance里已经有了地址就会直接返回 , 但是未初始化。在后续调用实例的属性/方法时会有问题!
class SingletonLazy{//加上volatile 禁止指令重排序private volatile static SingletonLazy instance = null;public static SingletonLazy getInstance(){if (instance == null) {synchronized (SingletonLazy.class) {if (instance == null) {instance = new SingletonLazy();}}}return instance;}private SingletonLazy(){}
}
相关文章:
多线程---单例模式
文章目录 什么是单例模式?饿汉模式懒汉模式版本一:最简单的懒汉模式版本二:考虑懒汉模式存在的线程安全问题版本三:更完善的解决线程安全问题版本四:解决指令重排序问题 什么是单例模式? 单例模式…...

SpringBoot相比于Spring的优点(自动配置和依赖管理)
自动配置 例子见真章 我们先看一下我们Spring整合Druid的过程,以及我们使用SpringBoot整合Druid的过程我们就知道我们SpringBoot的好处了。 Spring方式 Spring方式分为两种,第一种就是我们使用xml进行整合,第二种就是使用我们注解进行简化…...

SAP SPAD新建打印纸张
SAP SPAD新建打印纸张 1.事务代码SPAD 2.完全管理-设备类型-页格式-显示(创建格式页) 3.按标准A4纸张为模板参考创建。同一个纸张纵向/横向各创建1次(创建格式页) 4.完全管理-设备类型-格式类型-显示(创建格式类型࿰…...

C# 图解教程 第5版 —— 第11章 结构
文章目录 11.1 什么是结构11.2 结构是值类型11.3 对结构赋值11.4 构造函数和析构函数11.4.1 实例构造函数11.4.2 静态构造函数11.4.3 构造函数和析构函数小结 11.5 属性和字段初始化语句11.6 结构是密封的11.7 装箱和拆箱(*)11.8 结构作为返回值和参数11…...

车载电子电器架构 —— 基于AP定义车载HPC
我是穿拖鞋的汉子,魔都中坚持长期主义的汽车电子工程师。 老规矩,分享一段喜欢的文字,避免自己成为高知识低文化的工程师: 屏蔽力是信息过载时代一个人的特殊竞争力,任何消耗你的人和事,多看一眼都是你的不对。非必要不费力证明自己,无利益不试图说服别人,是精神上的节…...

Redis原理-IO模型和持久化
高性能IO模型 为什么单线程Redis能那么快 一方面,Redis 的大部分操作在内存上完成,再加上它采用了高效的数据结构,例如哈希表和跳表,这是它实现高性能的一个重要原因。另一方面,就是 Redis 采用了多路复用机制&#…...

PID控制示例
PID控制简单示例 import numpy as np import matplotlib.pyplot as plt import copy# 定义曲线函数 y sin(x) def target_curve(x):return np.sin(x)class PID:def __init__(self, kp, ki, kd):self.kp kpself.ki kiself.kd kdself.ep 0.0self.ei 0.0self.ed 0.0self.d…...

GoLand GC(垃圾回收机制)简介及调优
GC(Garbage Collector)垃圾回收机制及调优 简单理解GC机制 其实gc机制特别容易理解,就是物理内存的自动清理工。我们可以把内存想象成一个房间,程序运行时会在这个房间里存放各种东西,但有时候我们会忘记把不再需要的东西拿出去,…...

AI:40-基于深度学习的森林火灾识别
🚀 本文选自专栏:AI领域专栏 从基础到实践,深入了解算法、案例和最新趋势。无论你是初学者还是经验丰富的数据科学家,通过案例和项目实践,掌握核心概念和实用技能。每篇案例都包含代码实例,详细讲解供大家学习。 📌📌📌本专栏包含以下学习方向: 机器学习、深度学…...

37基于MATLAB平台的图像去噪,锐化,边缘检测,程序已调试通过,可直接运行。
基于MATLAB平台的图像去噪,锐化,边缘检测,程序已调试通过,可直接运行。 37matlab边缘检测图像处理 (xiaohongshu.com)...

通过Metasploit+Ngrok穿透内网长期维持访问外网Android设备
前言: 因为之前作为小白我不会在Kali Linux里面把IP映射出外网,卡在那个地方很久,后来解决了这个问题就写方法出来和大家分享分享。 环境: Kali Linux系统(https://www.kali.org/downloads/) Metasploit Ngrok Linux64位的端口转发工具(htt…...
STM32 CubeMX配置USB HID功能,及安装路径
STM32CubeMX学习笔记(46)——USB接口使用(HID自定义设备) STM32CubeMX实现STM32 USBHID双向64字节通信(下位机部分) STM32 USB HID设置(STM32CubeMX) 关于keil 5安装出现Fail to set path to Software Packs.问题解决方法...

【错误解决方案】ModuleNotFoundError: No module named ‘transformers‘
1. 错误提示 在python程序中,尝试导入一个名为transformers的模块,但Python提示找不到这个模块。 错误提示:ModuleNotFoundError: No module named ‘transformers‘ 2. 解决方案 所遇到的问题是Python无法找到名为transformers的模块&am…...

Mac 配置环境变量
Mac 配置环境变量 修改配置文件 vim ~/.bash_profile i进入编辑模式. Esc:wq 保存文件 esc:q 退出 如:jdk环境变量配置 JAVA_HOME/Library/Java/JavaVirtualMachines/jdk1.8.0_361.jdk/Contents/Home CLASSPATH J A V A H O M E / l i b / t o o l…...

如何在linux服务器上安装Anaconda与pytorch,以及pytorch卸载
如何在linux服务器上安装Anaconda与pytorch,以及pytorch卸载 1,安装anaconda1.1 下载anaconda安装包1.2 安装anaconda1.3 设计环境变量1.4 安装完成验证 2 Anaconda安装pytorch2.1 创建虚拟环境2.2 查看现存环境2.3 激活环境2.4 选择合适的pytorch版本下…...

ansble
ansble概述 Ansible是一款自动化运维工具,基于Python开发,具有批量系统配置,批量程序部署, 批量运行命令等功能。 Ansible的很多模块在执行时都会先判断目标节点是否要执行任务,所以,可以放心大胆地让Ansible去执行任务…...
git常见命令(持续更新)
判断是否为git项目 一个repo可以由多个git项目组成,一般每个git项目的根目录下都会有**.git**的文件夹;使用任何git命令前都需要打开到git项目文件下面。 git log 不带参数 // 查看本次commit修改的地方 git log-p // 可以查看FileName从建立到现在…...
Python基础入门例程23-NP23 删除好友(列表)
最近的博文: Python基础入门例程22-NP22 删除简历(列表)-CSDN博客 Python基础入门例程21-NP21 增加派对名单(二)(列表)-CSDN博客 Python基础入门例程20-NP20 增加派对名单(一&#x…...
识别鼠标选中actor_vtkInteractorStyleTrackballActor
开发环境: Windows 11 家庭中文版Microsoft Visual Studio Community 2019VTK-9.3.0.rc0vtk-example参考代码目的:学习与总结 demo解决问题:通过自定义vtkInteractorStyle类中成员函数OnLeftButtonDown,判断鼠标当前选中的是哪个…...
C++ Qt关于启动可执行文件存在的问题
如果软件具有管理员权限。请略过 使用QProcess 如果不具有管理员权限 启动可执行文件,在Debug和Release中没有问题,但是如果可执行文件启动需要管理员权限,调用函数startDetached,win10/11去要在点击用户账户控制弹窗 当使用I…...

51c自动驾驶~合集58
我自己的原文哦~ https://blog.51cto.com/whaosoft/13967107 #CCA-Attention 全局池化局部保留,CCA-Attention为LLM长文本建模带来突破性进展 琶洲实验室、华南理工大学联合推出关键上下文感知注意力机制(CCA-Attention),…...

微服务商城-商品微服务
数据表 CREATE TABLE product (id bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT 商品id,cateid smallint(6) UNSIGNED NOT NULL DEFAULT 0 COMMENT 类别Id,name varchar(100) NOT NULL DEFAULT COMMENT 商品名称,subtitle varchar(200) NOT NULL DEFAULT COMMENT 商…...
【C语言练习】080. 使用C语言实现简单的数据库操作
080. 使用C语言实现简单的数据库操作 080. 使用C语言实现简单的数据库操作使用原生APIODBC接口第三方库ORM框架文件模拟1. 安装SQLite2. 示例代码:使用SQLite创建数据库、表和插入数据3. 编译和运行4. 示例运行输出:5. 注意事项6. 总结080. 使用C语言实现简单的数据库操作 在…...
精益数据分析(97/126):邮件营销与用户参与度的关键指标优化指南
精益数据分析(97/126):邮件营销与用户参与度的关键指标优化指南 在数字化营销时代,邮件列表效度、用户参与度和网站性能等指标往往决定着创业公司的增长成败。今天,我们将深入解析邮件打开率、网站可用性、页面参与时…...

OPenCV CUDA模块图像处理-----对图像执行 均值漂移滤波(Mean Shift Filtering)函数meanShiftFiltering()
操作系统:ubuntu22.04 OpenCV版本:OpenCV4.9 IDE:Visual Studio Code 编程语言:C11 算法描述 在 GPU 上对图像执行 均值漂移滤波(Mean Shift Filtering),用于图像分割或平滑处理。 该函数将输入图像中的…...

NXP S32K146 T-Box 携手 SD NAND(贴片式TF卡):驱动汽车智能革新的黄金组合
在汽车智能化的汹涌浪潮中,车辆不再仅仅是传统的交通工具,而是逐步演变为高度智能的移动终端。这一转变的核心支撑,来自于车内关键技术的深度融合与协同创新。车载远程信息处理盒(T-Box)方案:NXP S32K146 与…...
MySQL JOIN 表过多的优化思路
当 MySQL 查询涉及大量表 JOIN 时,性能会显著下降。以下是优化思路和简易实现方法: 一、核心优化思路 减少 JOIN 数量 数据冗余:添加必要的冗余字段(如订单表直接存储用户名)合并表:将频繁关联的小表合并成…...

【C++进阶篇】智能指针
C内存管理终极指南:智能指针从入门到源码剖析 一. 智能指针1.1 auto_ptr1.2 unique_ptr1.3 shared_ptr1.4 make_shared 二. 原理三. shared_ptr循环引用问题三. 线程安全问题四. 内存泄漏4.1 什么是内存泄漏4.2 危害4.3 避免内存泄漏 五. 最后 一. 智能指针 智能指…...

PHP 8.5 即将发布:管道操作符、强力调试
前不久,PHP宣布了即将在 2025 年 11 月 20 日 正式发布的 PHP 8.5!作为 PHP 语言的又一次重要迭代,PHP 8.5 承诺带来一系列旨在提升代码可读性、健壮性以及开发者效率的改进。而更令人兴奋的是,借助强大的本地开发环境 ServBay&am…...

李沐--动手学深度学习--GRU
1.GRU从零开始实现 #9.1.2GRU从零开始实现 import torch from torch import nn from d2l import torch as d2l#首先读取 8.5节中使用的时间机器数据集 batch_size,num_steps 32,35 train_iter,vocab d2l.load_data_time_machine(batch_size,num_steps) #初始化模型参数 def …...