1.单例模式
目录
简介
饿汉式
懒汉式
双重检测锁式
静态内部类式
枚举单例
测试
测试单例模式:
测试五种单例模式在多线程环境下的效率
问题(拓展)
例:反射破解单例模式
例:反序列化破解单例模式
总结:如何用
简介
单例对象(Singleton)是一种常用的设计模式。在Java应用中,单例对象能保证在一个 JVM 中,该对象只有一个实例存在。这样的模式有几个好处:
单例模式的优点:
- 由于单例模式只生产一个实例,减少了系统性能开销,当一个对象的产生需要比较多的资源时,如读取配置、产生其他依赖对象时,则可以通过在应用启动时直接产生一个单例对象,然后永久驻留内存的方式来解决
- 单例模式可以在系统设置全局的访问点,优化环境共享资源访问,例如可以设计一个单例类,负责所以数据表的映射处理
常见的五种单例模式实现方式:
- 主要:
- 饿汉式(线程安全,调用效率高;但是,不能延迟加载)
- 懒汉式(线程安全,调用效率不高;但是,可以延迟加载)
- 其他:
- 双重检测锁式(由于 JVM 底层内部模型原因,偶尔会出问题,不建议使用)
- 静态内部类式(线程安全,调用效率高;但是,可以延时加载)
- 枚举单例(线程安全,调用效率高,不能延时加载)
饿汉式
/*** @ProjectName:* @Package: com.example.gof23.creational_patterns.singleton* @ClassName: SingletonHg* @Description: 饿汉式单例模式(Hungry)* @Author: qfxl* @CreateDate: 2024/09/09 23:00* @Version: 1.0.0*/
public class SingletonHungry {//类初始化时,立即加载这个对象//(在类加载器加载时,是天然的线程安全模式;同时因为是立即加载,所以没有延迟加载的优势)private static SingletonHungry instance = new SingletonHungry();//私有化构造器private SingletonHungry() {}//方法没有同步,调用效率高public static SingletonHungry getInstance() {return instance;}
}
懒汉式
/*** @ProjectName:* @Package: com.example.gof23.creational_patterns.singleton* @ClassName: SingletonLazy* @Description: 懒汉式单例模式(Lazy)* @Author: qfxl* @CreateDate: 2024/09/09 23:00* @Version: 1.0.0*/
public class SingletonLazy {//类初始化时,不初始化这个对象(实现懒加载 或者叫 延迟加载(lazy load),真正用到的时候才加载)private static SingletonLazy instance;//私有化构造器private SingletonLazy() {}//方法同步,调用效率低public static synchronized SingletonLazy getInstance() {if (instance == null) {instance = new SingletonLazy();}return instance;}
}
双重检测锁式
/*** @ProjectName:* @Package: com.example.gof23.creational_patterns.singleton* @ClassName: SingletonDC* @Description: 双重检测锁式单例模式(Double Checked Locking)* @Author: qfxl* @CreateDate: 2024/09/09 23:10* @Version: 1.0.0*/
public class SingletonDC {//使用了volatile关键字后,重排序被禁止,所有的写(write)操作都将发生在读(read)操作之前private volatile static SingletonDC instance;//私有化构造器private SingletonDC() {}//双重检测锁式public SingletonDC getInstance() {if (instance == null) {synchronized (SingletonDC.class) {if (instance == null) {instance = new SingletonDC();}}}return instance;}
}
静态内部类式
/*** @ProjectName:* @Package: com.example.gof23.creational_patterns.singleton* @ClassName: SingletonSIC* @Description: 静态内部类式单例模式(Static Inner Class)* @Author: qfxl* @CreateDate: 2024/09/09 23:10* @Version: 1.0.0*/
public class SingletonSIC {private static class SingletonClassInstance {private static final SingletonSIC instance = new SingletonSIC();}//私有化构造器private SingletonSIC() {}public static SingletonSIC getInstance(){return SingletonClassInstance.instance;}
}
枚举单例
/*** @ProjectName:* @Package: com.example.gof23.creational_patterns.singleton* @ClassName: SingletonEnum* @Description: 枚举类单例模式(Enum)* @Author: qfxl* @CreateDate: 2024/09/09 23:10* @Version: 1.0.0*/
public enum SingletonEnum {//这个枚举元素,本身就是单例对象(没有延时加载)INSTANCE;//添加自己需要的操作public void singletonOperation() {}
}
测试
测试单例模式:
public class Client {public static void main(String[] args) {//测试饿汉式单例模式(Hungry)SingletonHungry hungry1 = SingletonHungry.getInstance();SingletonHungry hungry2 = SingletonHungry.getInstance();System.out.println(hungry1);System.out.println(hungry2);//测试懒汉式单例模式SingletonLazy lazy1 = SingletonLazy.getInstance();SingletonLazy lazy2 = SingletonLazy.getInstance();System.out.println(lazy1);System.out.println(lazy2);//测试双重检测锁单例模式SingletonDC dc1 = SingletonDC.getInstance();SingletonDC dc2 = SingletonDC.getInstance();System.out.println(dc1);System.out.println(dc2);//测试静态内部类式单例模式SingletonSIC sic1 = SingletonSIC.getInstance();SingletonSIC sic2 = SingletonSIC.getInstance();System.out.println(sic1);System.out.println(sic2);//测试枚举单例模式SingletonEnum anEnum1 = SingletonEnum.INSTANCE;SingletonEnum anEnum2 = SingletonEnum.INSTANCE;System.out.println(anEnum1==anEnum2);}
}
结果为:
饿汉式:com.example.gof23.creational_patterns.singleton.SingletonHungry@1540e19d
饿汉式:com.example.gof23.creational_patterns.singleton.SingletonHungry@1540e19d
懒汉式:com.example.gof23.creational_patterns.singleton.SingletonLazy@677327b6
懒汉式:com.example.gof23.creational_patterns.singleton.SingletonLazy@677327b6
双重检测锁:com.example.gof23.creational_patterns.singleton.SingletonDC@14ae5a5
双重检测锁:com.example.gof23.creational_patterns.singleton.SingletonDC@14ae5a5
静态内部类:com.example.gof23.creational_patterns.singleton.SingletonSIC@7f31245a
静态内部类:com.example.gof23.creational_patterns.singleton.SingletonSIC@7f31245a
枚举单例:true
测试五种单例模式在多线程环境下的效率
(关注相对值即可,不同的环境下测试值完全不一样)
| 五种单例模式 | 时间 |
|---|---|
| 饿汉式(SingletonHungry) | 26ms |
| 懒汉式(SingletonLazy) | 186ms |
| 双重检测锁式(SingletonDC) | 40ms |
| 静态内部类式(SingletonSIC) | 31ms |
| 枚举单例(SingletonEnum) | 37ms |
CountDownLatch- 同步辅助类,在完全一组正在其他线程中执行的操作之前,它允许一个或多个线程一直等待
countDown():当前线程调用此方法,则计数减一(建议放在 finally 里执行)await():调用此方法会一直阻塞当前线程,直到计时器的值为0
public class ClientTimes {public static void main(String[] args) throws InterruptedException {long start = System.currentTimeMillis();int threadNum = 10;final CountDownLatch countDownLatch = new CountDownLatch(threadNum);for (int i = 0; i < threadNum; i++) {new Thread(new Runnable() {public void run() {for (int i = 0; i < 1000000; i++) {//分别对下面的单例模式进行测试SingletonHungry hungry = SingletonHungry.getInstance();
// SingletonLazy lazy = SingletonLazy.getInstance();
// SingletonDC dc = SingletonDC.getInstance();
// SingletonSIC sic = SingletonSIC.getInstance();
// SingletonEnum anEnum = SingletonEnum.INSTANCE;}countDownLatch.countDown();}}).start();}//main线程阻塞,直到计数器变为0,才会继续执行countDownLatch.await();long end = System.currentTimeMillis();System.out.println("总耗时:" + (end - start));}
}
测试结果如上表格
问题(拓展)
- 反射可以破解上面几种(不包含枚举式)实现反式(可以在构造方法中手动抛出异常控制)
- 反序列化可以破解上面几种(不包含枚举式)实现方式(可以通过定义 readResolver() 防止获得不同的对象)
- 反序列化时,如果对象所在的类定义了 readResolver(),(实际是一种回调),定义返回那个对象
例:反射破解单例模式
package com.example.gof23.creational_patterns.singleton.expand;public class SingletonDemo {private static SingletonDemo instance = new SingletonDemo();//私有化构造器private SingletonDemo() {}public static SingletonDemo getInstance() {return instance;}}
public class Test_reflect {public static void main(String[] args) throws Exception {//通过反射来破解单例模式(通过反射的方式直接调用私有化构造器)Class<SingletonDemo> clazz = (Class<SingletonDemo>) Class.forName("com.example.gof23.creational_patterns.singleton.expand.SingletonDemo");Constructor<SingletonDemo> c = clazz.getDeclaredConstructor(null);c.setAccessible(true);//跳过权限的检测,使其可以访问私有的方法SingletonDemo sd1 = c.newInstance();SingletonDemo sd2 = c.newInstance();System.out.println(sd1);System.out.println(sd2);}
}
结果为:
com.example.gof23.creational_patterns.singleton.expand.SingletonDemo@1540e19d
com.example.gof23.creational_patterns.singleton.expand.SingletonDemo@677327b6
防止反射破解单例模式:在构造方法中手动抛出异常控制
package com.example.gof23.creational_patterns.singleton.expand;public class SingletonDemo {private static SingletonDemo instance = new SingletonDemo();//私有化构造器private SingletonDemo() {//防止反射获取私有化的构造方法,从而破解单例模式if (instance != null) {throw new RuntimeException();}}public static SingletonDemo getInstance() {return instance;}}
再运行的结果为:
com.example.gof23.creational_patterns.singleton.expand.SingletonDemo@135fbaa4
com.example.gof23.creational_patterns.singleton.expand.SingletonDemo@135fbaa4
例:反序列化破解单例模式
package com.example.gof23.creational_patterns.singleton.expand;import java.io.Serializable;public class SingletonDemo implements Serializable {private static SingletonDemo instance = new SingletonDemo();//私有化构造器private SingletonDemo() {}public static SingletonDemo getInstance() {return instance;}}
public class Test_serializable {public static void main(String[] args) throws Exception {//通过反序列化的方式构造多个对象SingletonDemo instance1 = SingletonDemo.getInstance();FileOutputStream fos = new FileOutputStream("e:/a.txt");ObjectOutputStream oos = new ObjectOutputStream(fos);oos.writeObject(instance1);FileInputStream fis = new FileInputStream("e:/a.txt");ObjectInputStream ois = new ObjectInputStream(fis);SingletonDemo instance2 = (SingletonDemo) ois.readObject();System.out.println(instance1);System.out.println(instance2);}
}
结果为:
com.example.gof23.creational_patterns.singleton.expand.SingletonDemo@135fbaa4
com.example.gof23.creational_patterns.singleton.expand.SingletonDemo@58372a00
防止反序列化破解单例模式:通过定义 readResolver() 防止获得不同的对象
package com.example.gof23.creational_patterns.singleton.expand;import java.io.Serializable;public class SingletonDemo implements Serializable {private static SingletonDemo instance = new SingletonDemo();//私有化构造器private SingletonDemo() {//防止反射获取私有化的构造方法,从而破解单例模式if (instance != null) {throw new RuntimeException();}}public static SingletonDemo getInstance() {return instance;}//在反序列化时,如果定义了此方法,则直接返回此方法中的对象,无需单独再创建新对象private Object readResolve() {return instance;}}
再运行结果为:
com.example.gof23.creational_patterns.singleton.expand.SingletonDemo@135fbaa4
com.example.gof23.creational_patterns.singleton.expand.SingletonDemo@135fbaa4
总结:如何用
- 单例对象占用资源少,不需要延迟加载:
- 枚举式 好于 饿汉式
- 单例对象占用资源大,需要延迟加载:
- 静态内部类式 好于 懒汉式
相关文章:
1.单例模式
目录 简介 饿汉式 懒汉式 双重检测锁式 静态内部类式 枚举单例 测试 测试单例模式: 测试五种单例模式在多线程环境下的效率 问题(拓展) 例:反射破解单例模式 例:反序列化破解单例模式 总结:如何…...
数据倾斜问题
数据倾斜:主要就是在处理MR任务的时候,某个reduce的数据处理量比另外一些的reduce的数据量要大得多,其他reduce几乎不处理,这样的现象就是数据倾斜。 官方解释:数据倾斜指的是在数据处理过程中,由于某些键…...
大龄焦虑?老码农逆袭之路:拥抱大模型时代,焕发职业生涯新活力!
其实我很早就对大龄程序员这个话题感到焦虑,担心自己35岁之后会面临失业,有时和亲戚朋友聊天时,也会经常拿这个出来调侃。现在身边已经有很多35岁左右的同事,自己过两年也会步入35岁的行列,反倒多了一份淡定和从容。 …...
Vue 页面反复刷新常见问题及解决方案
Vue 页面反复刷新常见问题及解决方案 引言 Vue.js 是一个流行的前端框架,旨在通过其响应式的数据绑定和组件化的开发模式简化开发。然而,在开发 Vue.js 应用时,页面反复刷新的问题可能会对用户体验和开发效率产生负面影响。本文将深入探讨 …...
Windows上指定盘符-安装WSL虚拟机(机械硬盘)
参考来自于教程1:史上最全的WSL安装教程 - 知乎 (zhihu.com)https://zhuanlan.zhihu.com/p/386590591#%E4%B8%80%E3%80%81%E5%AE%89%E8%A3%85WSL2.0 教程2:Windows 10: 将 WSL Linux 实例安装到 D 盘,做成移动硬盘绿色版也不在话下 - 知乎 (z…...
ffmpeg实现视频的合成与分割
视频合成与分割程序使用 作者开发了一款软件,可以实现对视频的合成和分割,界面如下: 播放时,可以选择多个视频源;在选中“保存视频”情况下,会将多个视频源合成一个视频。如果只取一个视频源中一段视频…...
团体标准的十大优势
一、团体标准是什么 团体标准是指由社会团体(行业协会、联合会、企业联盟等)按照自己确立的制定程序,自主制定、发布、采纳,并由社会自愿采用的标准。简单的说,就是社会团体为了满足市场和创新需要,协调相…...
java spring boot 动态添加 cron(表达式)任务、动态添加停止单个cron任务
java spring boot 动态添加 cron(表达式)任务、动态添加停止单个cron任务 添加对应的maven <dependency><groupId>org.quartz-scheduler</groupId><artifactId>quartz</artifactId><version>2.3.0</version…...
sqlgun靶场漏洞挖掘
1.xss漏洞 搜索框输入以下代码,验证是否存在xss漏洞 <script>alert(1)</script> OK了,存在xss漏洞 2.SQL注入 经过测试,输入框存在SQL注入漏洞 查询数据库名 查询管理员账号密码 此处密码为MD5加密,解码内容如下 找…...
好用的 Markdown 编辑器组件
ByteMD bytedance/bytemd: ByteMD v1 repository (github.com) 这里由于我的项目是 Next,所以安装 bytemd/react, 阅读官方文档,执行命令来安装编辑器主体、以及 gfm(表格支持)插件、highlight 代码高亮插件…...
uniapp vite3 require导入commonJS 的js文件方法
vite3 导入commonJS 方式导出 在Vite 3中,你可以通过配置vite.config.js来实现导入CommonJS(CJS)风格的模块。Vite 默认支持ES模块导入,但如果你需要导入CJS模块,可以使用特定的插件,比如originjs/vite-pl…...
通义灵码用户说:“人工编写测试用例需要数十分钟,通义灵码以毫秒级的速度生成测试代码,且准确率和覆盖率都令人满意”
通过一篇文章,详细跟大家分享一下我在使用通义灵码过程中的感受。 一、定义 通义灵码,是一个智能编码助手,它基于通义大模型,提供代码智能生成、研发智能问答能力。 在体验过程中有任何问题均可点击下面的连接前往了解和学习。 …...
MySQL中的约束
约束概述 1.1 为什么需要约束 数据完整性(Data Integrity)是指数据的精确性(Accuracy)和可靠性(Reliability)。它是防止数据库中存在不符合语义规定的数据和防止因错误信息的输入输出造成无效操作或错误信…...
Leetcode 寻找重复数
可以使用 位运算 来解决这道题目。使用位运算的一个核心思想是基于数字的二进制表示,统计每一位上 1 的出现次数,并与期望的出现次数做比较。通过这种方法,可以推断出哪个数字重复。 class Solution { public:int findDuplicate(vector<i…...
大一新生以此篇开启你的算法之路
各位大一计算机萌新们,你们好,本篇博客会带领大家进行算法入门,给各位大一萌新答疑解惑。博客文章略长,可根据自己的需要观看,在博客中会有给大一萌新问题的解答,请不要错过。 入门简介: 算法…...
【AI大模型】ChatGPT模型原理介绍(上)
目录 🍔 什么是ChatGPT? 🍔 GPT-1介绍 2.1 GPT-1模型架构 2.2 GPT-1训练过程 2.2.1 无监督的预训练语言模型 2.2.2 有监督的下游任务fine-tunning 2.2.3 整体训练过程架构图 2.3 GPT-1数据集 2.4 GPT-1模型的特点 2.5 GPT-1模型总结…...
基于UE5和ROS2的激光雷达+深度RGBD相机小车的仿真指南(五):Blender锥桶建模
前言 本系列教程旨在使用UE5配置一个具备激光雷达深度摄像机的仿真小车,并使用通过跨平台的方式进行ROS2和UE5仿真的通讯,达到小车自主导航的目的。本教程默认有ROS2导航及其gazebo仿真相关方面基础,Nav2相关的学习教程可以参考本人的其他博…...
C++竞赛初阶L1-15-第六单元-多维数组(34~35课)557: T456507 图像旋转
题目内容 输入一个 n 行 m 列的黑白图像,将它顺时针旋转 90 度后输出。 输入格式 第一行包含两个整数 n 和 m,表示图像包含像素点的行数和列数。1≤n≤100,1≤m≤100。 接下来 n 行,每行 m 个整数,表示图像的每个像…...
无线领夹麦克风哪个牌子好?西圣、罗德、猛犸领夹麦克风深度评测
如今短视频和直播行业蓬勃发展,无线领夹麦克风成为了许多创作者不可或缺的工具。然而,市场上的无线领夹麦克风品牌众多、质量参差不齐,为了帮助大家挑选到满意的产品,我作为数码测评博主,对无线领夹麦克风市场进行了…...
React Native 0.76,New Architecture 将成为默认模式,全新的 RN 来了
关于 React Native 的 New Architecture 概念,最早应该是从 2018 年 RN 团队决定重写大量底层实现开始,因为那时候 React Native 面临各种结构问题和性能瓶颈,最终迫使 RN 团队开始进行重构。 而从 React Native 0.68 开始,New A…...
MFC内存泄露
1、泄露代码示例 void X::SetApplicationBtn() {CMFCRibbonApplicationButton* pBtn GetApplicationButton();// 获取 Ribbon Bar 指针// 创建自定义按钮CCustomRibbonAppButton* pCustomButton new CCustomRibbonAppButton();pCustomButton->SetImage(IDB_BITMAP_Jdp26)…...
java 实现excel文件转pdf | 无水印 | 无限制
文章目录 目录 文章目录 前言 1.项目远程仓库配置 2.pom文件引入相关依赖 3.代码破解 二、Excel转PDF 1.代码实现 2.Aspose.License.xml 授权文件 总结 前言 java处理excel转pdf一直没找到什么好用的免费jar包工具,自己手写的难度,恐怕高级程序员花费一年的事件,也…...
STM32+rt-thread判断是否联网
一、根据NETDEV_FLAG_INTERNET_UP位判断 static bool is_conncected(void) {struct netdev *dev RT_NULL;dev netdev_get_first_by_flags(NETDEV_FLAG_INTERNET_UP);if (dev RT_NULL){printf("wait netdev internet up...");return false;}else{printf("loc…...
1.3 VSCode安装与环境配置
进入网址Visual Studio Code - Code Editing. Redefined下载.deb文件,然后打开终端,进入下载文件夹,键入命令 sudo dpkg -i code_1.100.3-1748872405_amd64.deb 在终端键入命令code即启动vscode 需要安装插件列表 1.Chinese简化 2.ros …...
【ROS】Nav2源码之nav2_behavior_tree-行为树节点列表
1、行为树节点分类 在 Nav2(Navigation2)的行为树框架中,行为树节点插件按照功能分为 Action(动作节点)、Condition(条件节点)、Control(控制节点) 和 Decorator(装饰节点) 四类。 1.1 动作节点 Action 执行具体的机器人操作或任务,直接与硬件、传感器或外部系统…...
【HTTP三个基础问题】
面试官您好!HTTP是超文本传输协议,是互联网上客户端和服务器之间传输超文本数据(比如文字、图片、音频、视频等)的核心协议,当前互联网应用最广泛的版本是HTTP1.1,它基于经典的C/S模型,也就是客…...
全面解析各类VPN技术:GRE、IPsec、L2TP、SSL与MPLS VPN对比
目录 引言 VPN技术概述 GRE VPN 3.1 GRE封装结构 3.2 GRE的应用场景 GRE over IPsec 4.1 GRE over IPsec封装结构 4.2 为什么使用GRE over IPsec? IPsec VPN 5.1 IPsec传输模式(Transport Mode) 5.2 IPsec隧道模式(Tunne…...
3-11单元格区域边界定位(End属性)学习笔记
返回一个Range 对象,只读。该对象代表包含源区域的区域上端下端左端右端的最后一个单元格。等同于按键 End 向上键(End(xlUp))、End向下键(End(xlDown))、End向左键(End(xlToLeft)End向右键(End(xlToRight)) 注意:它移动的位置必须是相连的有内容的单元格…...
基于TurtleBot3在Gazebo地图实现机器人远程控制
1. TurtleBot3环境配置 # 下载TurtleBot3核心包 mkdir -p ~/catkin_ws/src cd ~/catkin_ws/src git clone -b noetic-devel https://github.com/ROBOTIS-GIT/turtlebot3.git git clone -b noetic https://github.com/ROBOTIS-GIT/turtlebot3_msgs.git git clone -b noetic-dev…...
面向无人机海岸带生态系统监测的语义分割基准数据集
描述:海岸带生态系统的监测是维护生态平衡和可持续发展的重要任务。语义分割技术在遥感影像中的应用为海岸带生态系统的精准监测提供了有效手段。然而,目前该领域仍面临一个挑战,即缺乏公开的专门面向海岸带生态系统的语义分割基准数据集。受…...
