创建型:单例模式

目录

1、核心思想

2、实现方式

2.1 饿汉式

2.2 懒汉式

2.3 枚举(Enum)

3、关键注意事项

3.1 线程安全

3.2 反射攻击

3.3 序列化与反序列化

3.4 克隆保护

4、适用场景


1、核心思想

目的:确保一个类仅有一个实例

功能:供全局访问点(通过静态方法或变量提供全局访问入口),可以选择延迟加载。

优点缺点
严格控制实例数量,节省资源可能隐藏类之间的依赖关系,降低可测试性
全局访问点方便管理共享资源违背单一职责原则(管理自身生命周期)
避免频繁创建销毁对象多线程环境需额外处理同步问题

2、实现方式

2.1 饿汉式

饿汉式:即在初始阶段就主动进行实例化,并时刻保持一种渴求的状态,无论此单例是否有人使用。

特点:类加载时立即创建实例,线程安全但可能浪费资源。

public class EagerSingleton {// static:在类加载时初始化,与类同在;  final:一旦被赋值不能被更改private static final EagerSingleton instance = new EagerSingleton();// 私有构造函数,禁止外部调用创建对象private EagerSingleton() {} public static EagerSingleton getInstance() {return instance;}
}

2.2 懒汉式

懒汉式:在第一次使用时,再进行初始化,防止没有人调用,提前初始化造成的资源浪费。

特点:延迟实例化,需处理线程安全问题。

1> 同步锁版本(不推荐)

public class SynchronizedSingleton {private static SynchronizedSingleton instance;private SynchronizedSingleton() {}public static synchronized SynchronizedSingleton getInstance() {if (instance == null) {instance = new SynchronizedSingleton();}return instance;}
}

注意: 变量不能使用final,会导致被初始化为null,之后不可赋值

缺点:线程还没进入方法内,就先加锁排队,造成线程阻塞,资源和时间的浪费。

2> 双重检查锁(Double-Checked Locking)

public class DCLSingleton {// volatile:防止指令重排序,保证变量值在各线程访问时的同步性、唯一性private static volatile DCLSingleton instance;private DCLSingleton() {}public static DCLSingleton getInstance() {if (instance == null) { // 第一次检查,放宽入口,保证线程并发高效性synchronized (DCLSingleton.class) {if (instance == null) { // 第二次检查,加锁同步,保证实例化单次运行instance = new DCLSingleton();}}}return instance;}
}

相比“懒汉模式”​,其实在大多数情况下我们通常会更多地使用“饿汉模式”​,原因在于这个单例迟早是要被实例化占用内存的,延迟懒加载的意义并不大,加锁解锁反而是一种资源浪费,同步更是会降低CPU的利用率,使用不当的话反而会带来不必要的风险。

2.3 枚举(Enum)

特点:天然防止反射和序列化攻击,线程安全(推荐方式)

public enum EnumSingleton {INSTANCE; // 这是一个单例对象public void doSomething() {// 业务方法}
}


3、关键注意事项

3.1 线程安全

多线程环境下需确保实例唯一性(如双重检查锁、枚举等)。

3.2 反射攻击

通过反射可绕过私有构造函数,需额外防护(如枚举或抛出异常)。

攻击示例:

// 反射攻击代码:
Class<?> clazz = Singleton.class;
Constructor<?> constructor = clazz.getDeclaredConstructor();
constructor.setAccessible(true); // 绕过 private 权限
Singleton hackedInstance = (Singleton) constructor.newInstance(); // 创建新实例!

防御方法:在构造方法中抛异常(检测是否已存在实例,若存在则抛出异常

private Singleton() {if (INSTANCE != null) {throw new IllegalStateException("单例已被创建,禁止反射调用!");}
}

3.3 序列化与反序列化

反序列化可能创建新实例,需实现 readResolve() 方法。

攻击示例:

// 序列化攻击代码:
Singleton instance1 = Singleton.getInstance();
// 序列化
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(bos);
oos.writeObject(instance1);
// 反序列化
ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
ObjectInputStream ois = new ObjectInputStream(bis);
Singleton instance2 = (Singleton) ois.readObject(); // 新实例!

防御方法:实现 readResolve() 方法,直接返回已有实例,覆盖反序列化逻辑。

public class Singleton implements Serializable {private static final Singleton INSTANCE = new Singleton();private Singleton() {}// 反序列化时直接返回 INSTANCEprotected Object readResolve() {return INSTANCE;}
}

3.4 克隆保护

重写 clone() 方法并抛出异常。

若单例类实现了 Cloneable 接口,并直接使用默认的 clone() 方法(或自定义实现未做防御),攻击者可以通过调用 clone() 创建新实例,破坏单例的唯一性。

如果类不实现 Cloneable 接口,调用 clone() 会抛出 CloneNotSupportedException。

即使类未实现 Cloneable,也可显式重写 clone() 方法禁止克隆:

public class Singleton {private static final Singleton INSTANCE = new Singleton();private Singleton() {}public static Singleton getInstance() {return INSTANCE;}// 防御 clone 攻击@Overrideprotected Object clone() throws CloneNotSupportedException {throw new CloneNotSupportedException("禁止克隆单例!");}
}

4、适用场景

  • 资源共享:如数据库连接池、线程池。

  • 配置管理:全局配置类避免重复加载。

  • 日志记录:统一日志写入入口。

  • 设备驱动:如打印机唯一控制实例。

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

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

相关文章

副业小程序YUERGS,从开发到变现

文章目录 我为什么写这个小程序网站转小程序有什么坑有什么推广渠道个人开发者如何变现简单介绍YUERGS小程序给独立开发者一点小建议 我为什么写这个小程序 关注我的粉丝应该知道&#xff0c;我在硕士阶段就已经掌握了小程序开发技能&#xff0c;并写了一个名为“约球online”…

React路由(React学习笔记_09)

React路由 1,路由基础 现代的前端应用大多都是SPA(单页应用程序)&#xff0c;也就是只有一个HTML页面的应用程序。因为它的用户体验更好、对服务器的压力更小&#xff0c;所以更受欢迎。为了有效的使用单个页面来管理原来多个页面的功能&#xff0c;前端路由应运而生。 1, 安装…

2009-2025计算机408统考真题及解析

整理2009-2025 年计算机408统考真题及解析PDF 目录树&#xff1a; └── 2025考研计算机408统考真题及答案&#xff08;回忆版&#xff09;.pdf ├── 2009-2024计算机408真题解析 │ ├── 2009年计算机408统考真题解析.pdf │ ├── 2010年计算机408统考真题解析.pdf …

Mysql、Oracle、Sql Server、达梦之间sql的差异

1&#xff1a;分页查询 Sql Server&#xff1a; <bind name"startRow" value"(page - 1) * limit 1"/> <bind name"endRow" value"page * limit"/> SELECT *FROM (SELECT ROW_NUMBER() OVER (<if test"sortZd!…

SQL Server 常用函数

一、字符串处理函数 1. CONCAT&#xff1a;拼接字符串 语法&#xff1a;CONCAT(string1, string2, ..., stringN) 实例&#xff1a; SELECT CONCAT(Hello, , World) AS Result; 输出&#xff1a; Result ------------- Hello World 2. SUBSTRING&#xff1a;截取子字符串 …

【通用大模型】Serper API 详解:搜索引擎数据获取的核心工具

Serper API 详解&#xff1a;搜索引擎数据获取的核心工具 一、Serper API 的定义与核心功能二、技术架构与核心优势2.1 技术实现原理2.2 对比传统方案的突破性优势 三、典型应用场景与代码示例3.1 SEO 监控系统3.2 竞品广告分析 四、使用成本与配额策略五、开发者注意事项六、替…

ABP vNext 多租户系统实现登录页自定义 Logo 的最佳实践

&#x1f680; ABP vNext 多租户系统实现登录页自定义 Logo 的最佳实践 &#x1f9ed; 版本信息与运行环境 ABP Framework&#xff1a;v8.1.5.NET SDK&#xff1a;8.0数据库&#xff1a;PostgreSQL&#xff08;支持 SQLServer、MySQL 等&#xff09;BLOB 存储&#xff1a;本地…

FastDFS分布式文件系统架构学习(一)

FastDFS分布式文件系统架构学习 1. FastDFS简介 FastDFS是一个开源的轻量级分布式文件系统&#xff0c;由淘宝资深架构师余庆设计并开发。它专为互联网应用量身定制&#xff0c;特别适合以中小文件&#xff08;如图片、文档、音视频等&#xff09;为载体的在线服务。FastDFS不…

基于单片机的防盗报警器设计与实现

标题:基于51单片机的防盗报警器设计 内容:1.摘要 本文围绕基于51单片机的防盗报警器设计展开。背景在于现代社会安全需求不断提高&#xff0c;传统防盗方式存在诸多不足。目的是设计一款成本低、可靠性高且易于使用的防盗报警器。方法上&#xff0c;以51单片机为核心控制单元&…

IDE/IoT/搭建物联网(LiteOS)集成开发环境,基于 LiteOS Studio + GCC + JLink

文章目录 概述LiteOS Studio不推荐&#xff1f;安装和使用手册呢?HCIP实验的源码呢&#xff1f; 软件和依赖安装软件下载软件安装插件安装依赖工具-方案2依赖工具-方案1 工程配置打开或新建工程板卡配置组件配置编译器配置-gcc工具链编译器配置-Makefile脚本其他配置编译完成 …

【高斯拟合最终篇】Levenberg-Marquardt(LM)算法

Levenberg-Marquardt(LM)算法是一种结合高斯-牛顿法和梯度下降法的优化方法,特别适合非线性最小二乘问题,如高斯函数拟合。它通过引入阻尼因子(damping factor)平衡高斯-牛顿法的快速收敛和梯度下降法的稳定性。以下是基于之前的 gaussian_fit.py,加入 LM 算法实现高斯拟…

信道编码技术介绍

信息与通信系统中的编码有4 种形式&#xff1a;信源编码、信道编码、密码编码和多址编码。 其中信道编码的作用是对信源经过压缩后的数据加一定数量受到控制的冗余&#xff0c;使得数据在传输中或接收中发生的差错可以被纠正或被发现&#xff0c;从而可以正确恢复出原始数据信息…

线性回归策略

一种基于ATR(平均真实范围)、线性回归和布林带的交易策略。以下是对该策略的全面总结和分析: 交易逻辑思路 1. 过滤条件: - 集合竞价过滤:在每个交易日的开盘阶段,过滤掉集合竞价产生的异常数据。 - 价格异常过滤:排除当天开盘价与最高价或最低价相同的情况,这…

WordPress Relevanssi插件时间型SQL注入漏洞(CVE-2025-4396)

免责声明 本文档所述漏洞详情及复现方法仅限用于合法授权的安全研究和学术教育用途。任何个人或组织不得利用本文内容从事未经许可的渗透测试、网络攻击或其他违法行为。使用者应确保其行为符合相关法律法规,并取得目标系统的明确授权。 对于因不当使用本文信息而造成的任何直…

支持selenium的chrome driver更新到136.0.7103.94

最近chrome释放新版本&#xff1a;136.0.7103.94 如果运行selenium自动化测试出现以下问题&#xff0c;是需要升级chromedriver才可以解决的。 selenium.common.exceptions.SessionNotCreatedException: Message: session not created: This version of ChromeDriver only su…

附加:TCP如何保障数据传输

附加&#xff1a;TCP如何保障数据传输 LS-NET-012-TCP的交互过程详解 TCP 如何保障数据传输 TCP&#xff08;Transmission Control Protocol&#xff0c;传输控制协议&#xff09;是互联网核心协议之一&#xff0c;负责在IP网络上提供可靠的、面向连接的数据传输服务。它位于T…

Unity 批量将图片从默认类型改为Sprite类型

先将该脚本放到Editor目录下 如何使用:选中目录,然后点击Tool里面的批量修改按钮 using System; using UnityEngine; using UnityEditor; using System.IO; using System.Linq;/// <summary> /// 此工具可以批量将图片类型修改为精灵 /// </summary> public clas…

2025认证杯数学建模C题思路+代码+模型:化工厂生产流程的预测和控制

2025认证杯数学建模C题思路代码模型&#xff0c;详细内容见文末名片 在化工厂的生产流程中&#xff0c;往往涉及到多个反应釜、管道和储罐等设备。在 流水线上也有每个位置的温度、压力、流量等诸多参数。只有参数处于正常范 围时&#xff0c;最终的产物才是合格的。这些参数…

Rust 学习笔记:关于 HashMap 的练习题

Rust 学习笔记&#xff1a;关于 HashMap 的练习题 Rust 学习笔记&#xff1a;关于 HashMap 的练习题以下代码能否通过编译&#xff1f;若能&#xff0c;输出是&#xff1f;以下代码能否通过编译&#xff1f;若能&#xff0c;输出是&#xff1f; Rust 学习笔记&#xff1a;关于 …

Vue-事件修饰符

事件修饰符 prevent &#xff08;阻止默认事件&#xff09; 超链接 点击事件 代码 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><title>事件修饰符</title><!-- 引入Vue --><script …