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…...
零门槛NAS搭建:WinNAS如何让普通电脑秒变私有云?
一、核心优势:专为Windows用户设计的极简NAS WinNAS由深圳耘想存储科技开发,是一款收费低廉但功能全面的Windows NAS工具,主打“无学习成本部署” 。与其他NAS软件相比,其优势在于: 无需硬件改造:将任意W…...
论文解读:交大港大上海AI Lab开源论文 | 宇树机器人多姿态起立控制强化学习框架(二)
HoST框架核心实现方法详解 - 论文深度解读(第二部分) 《Learning Humanoid Standing-up Control across Diverse Postures》 系列文章: 论文深度解读 + 算法与代码分析(二) 作者机构: 上海AI Lab, 上海交通大学, 香港大学, 浙江大学, 香港中文大学 论文主题: 人形机器人…...

跨链模式:多链互操作架构与性能扩展方案
跨链模式:多链互操作架构与性能扩展方案 ——构建下一代区块链互联网的技术基石 一、跨链架构的核心范式演进 1. 分层协议栈:模块化解耦设计 现代跨链系统采用分层协议栈实现灵活扩展(H2Cross架构): 适配层…...
爬虫基础学习day2
# 爬虫设计领域 工商:企查查、天眼查短视频:抖音、快手、西瓜 ---> 飞瓜电商:京东、淘宝、聚美优品、亚马逊 ---> 分析店铺经营决策标题、排名航空:抓取所有航空公司价格 ---> 去哪儿自媒体:采集自媒体数据进…...
大语言模型(LLM)中的KV缓存压缩与动态稀疏注意力机制设计
随着大语言模型(LLM)参数规模的增长,推理阶段的内存占用和计算复杂度成为核心挑战。传统注意力机制的计算复杂度随序列长度呈二次方增长,而KV缓存的内存消耗可能高达数十GB(例如Llama2-7B处理100K token时需50GB内存&a…...
pycharm 设置环境出错
pycharm 设置环境出错 pycharm 新建项目,设置虚拟环境,出错 pycharm 出错 Cannot open Local Failed to start [powershell.exe, -NoExit, -ExecutionPolicy, Bypass, -File, C:\Program Files\JetBrains\PyCharm 2024.1.3\plugins\terminal\shell-int…...
comfyui 工作流中 图生视频 如何增加视频的长度到5秒
comfyUI 工作流怎么可以生成更长的视频。除了硬件显存要求之外还有别的方法吗? 在ComfyUI中实现图生视频并延长到5秒,需要结合多个扩展和技巧。以下是完整解决方案: 核心工作流配置(24fps下5秒120帧) #mermaid-svg-yP…...
【Kafka】Kafka从入门到实战:构建高吞吐量分布式消息系统
Kafka从入门到实战:构建高吞吐量分布式消息系统 一、Kafka概述 Apache Kafka是一个分布式流处理平台,最初由LinkedIn开发,后成为Apache顶级项目。它被设计用于高吞吐量、低延迟的消息处理,能够处理来自多个生产者的海量数据,并将这些数据实时传递给消费者。 Kafka核心特…...

java高级——高阶函数、如何定义一个函数式接口类似stream流的filter
java高级——高阶函数、stream流 前情提要文章介绍一、函数伊始1.1 合格的函数1.2 有形的函数2. 函数对象2.1 函数对象——行为参数化2.2 函数对象——延迟执行 二、 函数编程语法1. 函数对象表现形式1.1 Lambda表达式1.2 方法引用(Math::max) 2 函数接口…...

边缘计算网关提升水产养殖尾水处理的远程运维效率
一、项目背景 随着水产养殖行业的快速发展,养殖尾水的处理成为了一个亟待解决的环保问题。传统的尾水处理方式不仅效率低下,而且难以实现精准监控和管理。为了提升尾水处理的效果和效率,同时降低人力成本,某大型水产养殖企业决定…...